How to Kill a Hanging Hyper-V VM

· by Vincent De Smet · Read in about 2 min · (424 Words)

After boasting how fast I got a NodeJS container to do play with some npm packages, as seen in my previous post, I crashed the Hyper-V VM I was using…

I accidentally disconnected the external hard disk from which the CoreOS VM was running (due to an ageing USB cable) and I could no longer shut it down. Asking Hyper-V to turn of the power didn’t work also. The Stop-VM cmdlet was quite useless.

Stop-VM -Force
#hanging...#

This was not the first time I faced this issue, but I couldn’t find my notes on how I fixed it last time (I remember it was possible to get the ProcessId from a Hyper-V VM and just kill the process, should be simple…), time to properly jot it down this time for future reference…

Solution

I started by looking at the Properties exposed by the Microsoft.HyperV.PowerShell.VirtualMachine object returned from the Get-VM cmdlet. Use the Get-Member cmdlet for this (or the GM alias) and filter for things such as «Process» and «Id» (still falling back to old command tools such as findstr out of habit…)

Get-VM | GM | findstr /I "id"
Get-VM | GM | findstr /I "proc"

Didn’t return what I was looking for…

Having a look at the Name and Id property gave me this:

Get-VM | ft Id, Name
Id                                   Name
--                                   ----
3b5532af-93ae-4aa5-86e3-474a9e3638a0 coreos2
5c46b6d3-d4c5-4cfb-8587-84bbdeb3158a Win2k12-Sql2k12-Sun442
d591db38-0cce-474c-99be-d076b312c553 Win2k3-SQL2008R2-Sun433
ea0c01ad-8c66-4f84-99f4-df80e40ef3da Win2k8-Ora11.2-Sun44

I did have to resort to Google and it turns out Hyper-V uses this Id when starting the VM Worker Process (vmwp), a TaskList showing the CommandLine will tell you that clearly:

Get-WmiObject win32_process -Filter "name like '%vmwp%'" | select CreationDate,ProcessId,CommandLine | ft -AutoSize

That’s all I needed to know to kill the VM

Stop-Process 13432

It’s always easier if you let the computer do the matching for you, This blog post shows you how, break tis down as follows:

  1. Get the VM Id parsed out of the CommandLine by splitting on the space and returning the 2nd element in the array (0-based indexing):

    Get-WmiObject win32_process -Filter "name like '%vmwp%'" | select {$_.CommandLine.split(" ")[1] }
    
  2. Use a Dictionary object to assign a proper name to the property:

    Get-WmiObject win32_process -Filter "name like '%vmwp%'" | select ProcessId, @{Label="VM.Id";Expression={$_.CommandLine.split(" ")[1]}}
    
  3. Pass this GUID to the Get-VM cmdlet and return the Name property from the Microsoft.HyperV.PowerShell.VirtualMachine Object associated with each running vmwp Process:

    Get-WmiObject Win32_Process -Filter "Name like '%vmwp%'" | select ProcessId, `
    @{Label="VM.Name";Expression={(Get-VM -Id $_.Commandline.split(" ")[1]).Name}}
    

Hyper-V restarted the VM as soon as its worker process died, but this time it was responding properly…