PowerShell Function to Prevent Starting Hyper-V VM’s that are Connected to an External Network

Beginning with Windows 8 (Professional and Enterprise Edition), Hyper-V is available on workstations that have a processor that supports SLAT (Second Level Address Translation). For specifics about the requirements, see the Client Hyper-V blog article on Microsoft TechNet. That means you have a Hypervisor running right on your desktop or laptop computer for free. With the price of hardware these days, your regular everyday computer can be spec'd out with an i7 processor, 16 gigabytes of memory, and one or more solid state drives and in addition to performing your everyday work on it, you have an awesome test environment without the need for additional physical computers.

Thanks to the server core (no-GUI) installation of newer versions of Windows Server, you can run a number of VM's on the previously referenced hardware with no issues. I have a domain controller, web server, and a couple of SQL servers all running on Windows Server 2012 R2 with the server core installation. I also have more than a half dozen test Windows 8.1 machines on that same hardware, all of which can be running at the same time if needed thanks to Hyper-V's dynamic memory feature.

All of that is well and fine until you decided to run something like the DHCP Server role on one of the servers in that test lab environment. Accidentally connect it to an external network and it could reap havoc on your production network to say the least.

That's why I created the following function to only boot VM's that are connected to internal or private network. It will also start VM's that are not connected to a network.

 1#Requires -Version 3.0
 2#Requires -Modules Hyper-V
 3function Start-MrVM {
 4
 5<#
 6.SYNOPSIS
 7    Starts Hyper-V VM's that are valid, not already running, and not connected
 8    to an external network.
 9
10.DESCRIPTION
11    Start-MrVM is a function that is designed to start a test lab environment of
12    VM's running on Hyper-V on a Windoes 8.1 machine. It is designed specifically
13    to prevent VM's that are connected to an external switch from being started
14    since this could interfere with a production environment because of the
15    potiential of things like a DHCP server running in the test VM environment.
16
17.PARAMETER VMName
18    The name of the VM(s) to start.
19
20.EXAMPLE
21     Start-MrVM -VMName DC01, SQL01, PC01
22
23.EXAMPLE
24     'DC01', 'SQL01', 'PC01' | Start-MrVM
25
26.EXAMPLE
27     Get-VM | Start-MrVM
28
29.INPUTS
30    String
31
32.OUTPUTS
33    None
34
35.NOTES
36    Author:  Mike F Robbins
37    Website: http://mikefrobbins.com
38    Twitter: @mikefrobbins
39#>
40
41    [CmdletBinding()]
42    param (
43        [Parameter(Mandatory,
44                   ValueFromPipeline,
45                   ValueFromPipelineByPropertyName)]
46        [Alias('Name')]
47        [string[]]$VMName
48    )
49
50    BEGIN {
51        try {
52            $VMs = Get-VM -ErrorAction Stop
53            $VMSwitches = Get-VMSwitch -SwitchType Internal, Private -ErrorAction Stop |
54                          Select-Object -ExpandProperty Name
55        }
56        catch {
57            Write-Warning -Message "An error has occured.  Error details: $_.Exception.Message"
58        }
59    }
60
61    PROCESS {
62        foreach ($v in $VMName) {
63
64            if ($VMs.Name -contains $v) {
65
66                $VM = $VMs | Where-Object Name -eq $v
67
68                if ($VM.State -ne 'Running') {
69
70                    $VMSwitch = $VM | Get-VMNetworkAdapter | Select-Object -ExpandProperty SwitchName
71
72                    if ($VMSwitches -contains $VMSwitch -or (-not($VMSwitch))) {
73
74                        Write-Verbose -Message "Starting VM: $($VM.Name)"
75
76                        try {
77                            Start-VM -Name $VM.VMName -ErrorAction Stop
78                        }
79                        catch {
80                            Write-Warning -Message "An error has occured.  Error details: $_.Exception.Message"
81                        }
82
83                    }
84                    else {
85                        Write-Warning -Message "VM: $($VM.Name) was not started because it's network is set to External!"
86                    }
87                }
88                else {
89                    Write-Warning -Message "VM: $($VM.Name) is Already Running!"
90                }
91            }
92            else {
93                Write-Warning -Message "VM: $v is invalid or was not found!"
94            }
95        }
96    }
97}

In the following example, an attempt is being made to start the VM's named DC01, SQL01, PC01, and PC02. The VM's are being specified via parameter input. DC01 is connected to an internal virtual switch, PC01 is set to Not Connected on its network adapter, PC02 is set to a private virtual switch, and SQL01 is set to an external virtual switch.

1. .\Start-MrVM.ps1
2Start-MrVM -VMName DC01, SQL01, PC01, PC02

start-mrvm1.jpg

Same network settings in the following example. This time DC01 is already running. The same computers are specified in this example except via pipeline input this time:

1'DC01', 'SQL01', 'PC01', 'PC02' | Start-MrVM

start-mrvm2.jpg

And this time, the Get-VM cmdlet which is part of the Hyper-V PowerShell module is being used to specify the VM's and the output of that cmdlet is being piped to my function.

1Get-VM -Name DC01, SQL01, PC01, PC02 | Start-MrVM -Verbose

start-mrvm3.jpg

Notice in the previous example, the verbose parameter was specified so you could see what VM's are attempting to be started.

µ