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.
#Requires -Version 3.0
#Requires -Modules Hyper-V
function Start-MrVM {
<#
.SYNOPSIS
Starts Hyper-V VM's that are valid, not already running, and not connected
to an external network.
.DESCRIPTION
Start-MrVM is a function that is designed to start a test lab environment of
VM's running on Hyper-V on a Windoes 8.1 machine. It is designed specifically
to prevent VM's that are connected to an external switch from being started
since this could interfere with a production environment because of the
potiential of things like a DHCP server running in the test VM environment.
.PARAMETER VMName
The name of the VM(s) to start.
.EXAMPLE
Start-MrVM -VMName DC01, SQL01, PC01
.EXAMPLE
'DC01', 'SQL01', 'PC01' | Start-MrVM
.EXAMPLE
Get-VM | Start-MrVM
.INPUTS
String
.OUTPUTS
None
.NOTES
Author: Mike F Robbins
Website: http://mikefrobbins.com
Twitter: @mikefrobbins
#>
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias('Name')]
[string[]]$VMName
)
BEGIN {
try {
$VMs = Get-VM -ErrorAction Stop
$VMSwitches = Get-VMSwitch -SwitchType Internal, Private -ErrorAction Stop |
Select-Object -ExpandProperty Name
}
catch {
Write-Warning -Message "An error has occured. Error details: $_.Exception.Message"
}
}
PROCESS {
foreach ($v in $VMName) {
if ($VMs.Name -contains $v) {
$VM = $VMs | Where-Object Name -eq $v
if ($VM.State -ne 'Running') {
$VMSwitch = $VM | Get-VMNetworkAdapter | Select-Object -ExpandProperty SwitchName
if ($VMSwitches -contains $VMSwitch -or (-not($VMSwitch))) {
Write-Verbose -Message "Starting VM: $($VM.Name)"
try {
Start-VM -Name $VM.VMName -ErrorAction Stop
}
catch {
Write-Warning -Message "An error has occured. Error details: $_.Exception.Message"
}
}
else {
Write-Warning -Message "VM: $($VM.Name) was not started because it's network is set to External!"
}
}
else {
Write-Warning -Message "VM: $($VM.Name) is Already Running!"
}
}
else {
Write-Warning -Message "VM: $v is invalid or was not found!"
}
}
}
}
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.
. .\Start-MrVM.ps1
Start-MrVM -VMName DC01, SQL01, PC01, PC02
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:
'DC01', 'SQL01', 'PC01', 'PC02' | Start-MrVM
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.
Get-VM -Name DC01, SQL01, PC01, PC02 | Start-MrVM -Verbose
Notice in the previous example, the verbose parameter was specified so you could see what VM’s are attempting to be started.
µ