Multi Server Management for Hyper-V (Part 3)

If you would like to be notified when Brien Posey releases the next part in this article series please sign up to our Real-Time Article Update newsletter.

If you would like to read the other parts in this article series please go to:


In the previous article in this series, I discussed two separate techniques for multi server management. First, I showed you how to create and use server groups in the Windows Server 2012 version of the Server Manager. After that, I walked you through the process of establishing a session with a remote server through PowerShell. Although both of these management techniques work well, neither of them are as powerful as the technique that I am going to demonstrate in this final article of the series.

Invoking a Command

PowerShell allows you to use the Invoke-Command cmdlet to run a command against one or more remote computers. To show you how this process works, I want to refer back to another command that I discussed earlier in this series. As you may recall, the Get-VM command is used to retrieve the names of all of the virtual machines that are running on a particular Hyper-V host. For the sake on demonstration, let’s pretend that we need to create a list of all of the virtual machine names along with the name of the host server on which the virtual machine resides, the virtual machine state, and its operational status. We can accomplish this by using the following command:

Get-VM | FT VMName, ComputerName, State, PrimaryStatusDescription

You can see what the output looks like in Figure A.

Figure A: You can use the Get-VM cmdlet to retrieve virtual machine information.

Now that I have demonstrated a useful PowerShell command, let’s make it even more useful by directing the command to run on multiple Hyper-V hosts. To do so, we will use the Invoke-Command cmdlet.

When you use the Invoke-Command cmdlet, you must specify the names of the computers that you want to run the command on (via the ComputerName parameter) and you must of course provide the command that you want to run. To show you how this works, suppose that I wanted to run the Get-VM command that I showed you earlier on two different Hyper-V hosts. For this example, I will use a server named Lab2 and a server named Prod2. The actual command that I would use is:

Invoke-Command –ComputerName Lab2, Prod2 { Get-VM | FT VMName, ComputerName, State, PrimaryStatusDescription}

Notice in the command above that the Invoke-Command cmdlet’s job is merely to redirect a command to the remote servers that are specified by the ComputerName parameter. The actual command that is to be run on the remote hosts must be included in braces {}. You can see the output of this command in Figure B.

Figure B: The Invoke-Command cmdlet can be used to redirect a PowerShell command to run on one or more remote servers.

As you can see in the figure above, two sets of output were returned because two separate Hyper-V hosts were specified.

Right now I’m sure that some of you are wondering if there is a way to combine the output of these commands rather than listing the output for each Hyper-V host separately. You can accomplish this by simply appending the ComputerName parameter to the Get-VM command. You don’t have to include the Invoke-Computer command. The actual command that you would use is:

Get-VM –ComputerName Lab2, Prod2 | FT VMName, ComputerName, State, PrimaryStatusDescription

As you can see in Figure C, this command creates a single lists of virtual machines. A quick check of the ComputerName field confirms that these virtual machines span multiple Hyper-V hosts.

Figure C: You can combine the command results into a single table.

Let’s Get Real

There is no denying that the technique that I just showed you is handy, especially when you consider that it can be applied to just about any Hyper-V related command. You can use this technique to perform all manner of bulk operations against your virtual machines.

Even so, the reality of the situation is that this technique can be a bit of a pain. In my previous example I used two different Hyper-V hosts, but many organizations have far more hosts than that. In my own organization I actually have six host servers.

Even manually listing six separate Hyper-V hosts isn’t that bad, but remember… The techniques that I have demonstrated were run against host servers. This same technique can also be used to run PowerShell commands against virtual machines. A single organization might have hundreds, or even thousands of virtual machines. You really don’t want to have to type all of those virtual machine names or host server names every time you want to run a bulk PowerShell command. Fortunately, you don’t have to. You can build text files containing names of virtual machines or names of host servers and then use those text files as input.

Working With Text Files

To show you how this works, I have created a text file named C:\Scripts\VMs.txt. This text file contains the names of some virtual machines. Keep in mind that you can get really creative with the use of these types of text files. For example, you might create a text file that acts as a list of virtualized domain controllers, or a text file that contains the names of virtualized Exchange servers.

In any case, parsing a text file is easy. If you simply want to see what’s in the text file, you can do so by using the Get-Content cmdlet and providing the path and filename of the text file. You can see what this looks like in Figure D.

Figure D: You can use the Get-Content cmdlet to display a text file’s contents.

Of course displaying a text file’s contents is one thing. Using the file’s contents within a command is something entirely different. Fortunately, we can easily use the Get-Content cmdlet to parse the list of computer names and use them within another command.

To show you how this works, I have created another text file called VMHosts.txt. I populated this text file with the names of my Hyper-V hosts. Now let’s use this text file to retrieve information about the virtual machines residing on each host. The actual command that we will use is:

Get-Content C:\Scripts\VMHosts.txt | ForEach-Object {Get-VM –ComputerName $_}

You can see the output from this command in Figure E.

Figure E: Virtual machine information is being displayed for hosts listed in a text file.

In case you are wondering, each line of the text file is assigned to a default variable named $_. As such, $_ represents the host name. This is why we are able to use a command string such as Get-VM –ComputerName $_.


I had originally planned to wrap up this article series with this article. However, there is one more trick that I want to show you. In Part 4, I want to show you how you can automate the creation of text files listing virtual machines or host servers. There are a number of different filtering criteria that you can use to compile a selective list of machines and then write that list to a specialized text file. For example, you might use a PowerShell command to build a text file containing a list of virtualized domain controllers.

If you would like to be notified when Brien Posey releases the next part in this article series please sign up to our Real-Time Article Update newsletter.

If you would like to read the other parts in this article series please go to:

About The Author

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top