Using PowerShell to locate a Hyper-V virtual machine

Hyper-V is a dynamic environment, and virtual machines can easily move from one host to another. Sometimes though, you may need to know which Hyper-V host a particular VM is running on so that you can perform some sort of management task against the VM. PowerShell makes it relatively easy to locate a single VM among a large number of Hyper-V hosts.

Finding a Hyper-V VM: The quick and dirty method

There are a few different ways of getting the job done, and the method that you will need to use will vary depending on how many hosts you have, and on how often you need to locate a specific VM. If you are just looking for a quick and dirty way to find a particular VM, then you can use a command like this one:

Get-VM -ComputerName ,, -VMName -ErrorAction SilentlyContinue | Select-Object VMName, ComputerName

If you were to run this command in real life, then you would replace <Host1>, <Host2>, and <Host3> with the names of your Hyper-V hosts (IP addresses only work under very specific circumstances). You would also replace <virtual machine name> with the name of the virtual machine that you are looking for.

When you run this command, it checks each of your Hyper-V hosts to see if the specified virtual machine exists. If the virtual machine does not exist on a particular host, then PowerShell hides the error message that would normally be displayed. If the virtual machine does exist, then PowerShell displays the virtual machine name and the name of the host on which the VM resides. You can see an example of this in the figure below.


As you can see in the figure, this technique works really well. Even so, there are a couple of disadvantages to using this method. First of all, the command requires you to type in the names or IP addresses of your Hyper-V hosts. That’s probably not a big deal if you only have a few hosts, but if you have more than three or four hosts, then this can quickly become a tedious chore.

The other disadvantage of this approach is that the command gives us the required information, but it doesn’t do anything with it. This approach would be a lot more useful if the VM name and the hostname were both written to variables so that we could run additional commands. For example, maybe we want to establish a remote session with the host or initiate a live migration or something like that. The whole thing could be automated if we could put the VM name and the name of its host into variables.

Utilizing a text file

One way of saving yourself some typing is to create a text file containing the names of your Hyper-V hosts. You can then tell PowerShell to read the names from this file so that you don’t have to type them each time.

For the purposes of this article, I have created a file named C:\Scripts\HostList.txt. This file lists the name or IP address of each of my Hyper-V hosts. Each host appears on a separate line. I then wrote a short script that does exactly the same thing as the command that I showed you earlier, except that it pulls the hostnames from my text file. Here is what the script looks like:

$HyperVHosts = Get-Content 'c:\scripts\HostList.txt'
ForEach ($IndividualHost in $HyperVHosts)
{
Get-VM -ComputerName $IndividualHost -VMName <Virtual Machine Name> -ErrorAction SilentlyContinue | Select-Object VMName, ComputerName
}

The first line of code tells PowerShell to read the file’s contents into a variable named $HyperVHosts. I then created a loop that examines each host listed within the text file. The host that is currently being checked is referenced by the variable $IndividalHost. You can see my code and the script’s output in the next figure.


Using variables

So far we have solved the problem of having to type a long list of hosts, but we still need to place the VM name and the name of its current host into variables that we can use for other purposes. If you look at the previous screen capture, you can see that I have hardcoded the name of the VM that I am looking for, but it would be just as easy to accept the VM name as input.

I accomplished this by adding one line of code to the beginning of the script:

$VM = Read-Host “Please enter the name of the virtual machine that you are looking for.”

This line prompts the user to enter a virtual machine name, and then writes that name to a variable called $VM. I then referenced this variable in the Get-VM command. You can see the script and its output in the figure below.

So now we have a variable that contains the virtual machine name. The last thing that we need to do is write the name of the virtual machine’s host to a variable. Here is how it’s done:

$VM = Read-Host "Please enter the name of the virtual machine that you are looking for."
$HyperVHosts = Get-Content 'c:\scripts\HostList.txt'
ForEach ($IndividualHost in $HyperVHosts)
{
Get-VM -ComputerName $IndividualHost -VMName $VM -ErrorAction SilentlyContinue | Tee-Object -Variable Temp | Out-Null
$VMHost = $Temp.ComputerName
}
Write-Host "The virtual machine " $VM " is hosted on " $VMHost

As you can see, I have significantly modified the Get-VM command. Initially, the Get-VM command tries to retrieve the specified VM from the host server that is currently being checked. Errors are also being suppressed, just as before. However, now I am using the Tee-Object command to write the output to a variable. I then appended the Out-Null cmdlet to prevent the results of the Get-VM cmdlet from being displayed onscreen.

The Tee-Object cmdlet creates a variable called $Temp, which contains the contents of the Get-VM cmdlet. Within the same loop, I am also creating a variable called $VMHost. This variable is assigned the contents of $Temp.ComputerName, which at some point will store the name of the host that is running the specified VM. You can see the script and its output in the figure below.

Final check

The script that I have created is simple enough that you shouldn’t have too much trouble with it. If you do run into problems though, there are three things that you should check.

1. Make sure that the host list text file lists hosts by name, not IP address.
2. Make sure that the computer on which you are running PowerShell can resolve the hostnames.
3. Make sure that all of the hosts (and the machine on which the script is running) are running similar versions of Windows. I ran into problems when I ran the script on a Windows Server 2016 machine, but the VM that I specified was hosted on Windows Server 2012 R2 Hyper-V.

Featured image: Pixabay

Brien Posey

Brien Posey is a freelance technology author and speaker with over two decades of IT experience. Prior to going freelance, Brien was a CIO for a national chain of hospitals and healthcare facilities. He has also served as a network engineer for the United States Department of Defense at Fort Knox. In addition, Brien has worked as a network administrator for some of the largest insurance companies in America. To date, Brien has received Microsoft’s MVP award numerous times in categories including Windows Server, IIS, Exchange Server, and File Systems / Storage. You can visit Brien’s Website at: www.brienposey.com.

Share
Published by
Brien Posey
Tags Powershell

Recent Posts

Azure DevOps Wiki: Manage your project documentation and collaboration

Not being able to find project documentation is way too common. Use Azure DevOps’ built-in…

2 days ago

Samsung Unpacked 2020: Galaxy S20, Galaxy Z Flip, and more

Samsung is again the first major company to roll out new smartphones in the new…

2 days ago

PhotoSquared data leak exposes users’ photos, information

PhotoSquared has experienced a data leak, mainly because the popular U.S.-based photo app failed to…

2 days ago

Moving data from an Azure VM to Storage Account with AzCopy

Here’s an elegant and modern way to move data from your Azure virtual machine to…

3 days ago

A lot not to like: Analysis of recent Facebook data breach

The effects of the recent Facebook data breach are still being felt. In this new…

3 days ago

Exchange 2019: Building an environment from scratch

Are you finally ready to take the plunge into Exchange 2019? If you are building…

3 days ago