VM Lab - Switch it up


Back again for another part in my VM Lab series.

So far I’ve created the folder structure which we will use to store our ISO files, VHD files [including template VHDs and Unattend.xml files] and VM’s. In order to manipulate the ReadOnly status of various files [such as the template VHD’s and Unattend.xml files], I’ve provided simple functions which will assist us.

Now we need to make sure that the final piece of the infrastructure is ready: the Hyper-V VM Switches.

Breakdown

As a change of scenery, this time I won’t just dump the code, I’ll try and explain my reasoning behind the code used. Since the 3 functions [again going for Get- , New- and Remove-] all use the same base structure, I thought it would be nice to explain some method to my madness. If this isn’t what you’ve come here for, please scroll down to the end of the page and just scoop the final code 🙂

There are only select options to choose when creating a VM Switch: External, Internal, Private (and in some versions NAT, but this is not included in my function for now). In order to limit the user’s choices, I’ve used something called ValidateSet, which gives the end user a predefined list of options to choose from. Should you manually enter a value which is not defined in the ValidateSet list, access will be denied.

You can find various examples in common Cmdlets, such as

1
Set-ExecutionPolicy -ExecutionPolicy

This will give you a predefined set of options to choose from, such as AllSigned, ByPass, Default, RemoteSigned, Restricted, Undefined and Unrestricted. In my code I limit the user to the default VM Switch types, but I also provide an option to select all 3 types at the same time, All.

1
[ValidateSet('Internal','External','Private','All')]

This does however require your function to be an advanced function, as defined by

1
[CmdletBinding()]

In case you didn’t know yet, adding something as simple as that will provide your function with additional features and functionality, such as being able to use CommonParameters, such as -Verbose or -WhatIf.

For a more in depth view of Standard functions vs Advanced functions, I’d like to refer to these great articles by the following great minds:

Now these are functions about VM Switches, but in my code I also use something called a switch statement. This allows me to set/change values, based on what value was chosen in my ValidateSet. There is a great article on Microsoft’s TechNet by The Scripting Guys, which will explain the entire concept better than I can do, so please have a look at that if anything is unclear about the options/usage of this statement.

In my case, this is the logic I used behind it:

At first I have defined all types of VM Switches as a variable

1
2
3
4
Write-Verbose 'Declaring variables'
        $Internal = $false
        $External = $false
        $Private = $false

Now through the switch statement, I check which $SwitchType has been selected and I change the accompanying variable to $true

1
2
3
4
5
6
switch ($SwitchType) {
            'Internal' {$Internal =$true}
            'External' {$External = $true}
            'Private' {$Private = $true}
            'All' {$Internal = $true ; $External = $true ; $Private = $true}
        }

After the variables are set to either $true or $false using the above mentioned switch statement, I use an if statement which will execute certain code if the value is set to $true. If the variable is set to $false,  you can have it do something else, of elseif, but for this code it wasn’t important.

1
2
3
4
5
6
7
8
9
if ($Internal) {
    Write-Verbose 'Checking for Internal switch'
    try {
        Get-VMSwitch -Name 'VMLab-Internal' -SwitchType Internal -ErrorAction Stop | Out-Null
        Write-Output 'VM Lab Internal switch is available'
    } catch {
        Write-Output 'Unable to find Internal VM Lab switch'
    }
}

By doing this, I can check each VM SwitchType, and if it was set as $true, I would either get, create or remove the VM Switch. In the above example I also use a try/catch block, but I will try and explain this in a future blog post.

Functions

As per usual, I’ve provided the final code below.

These functions are meant for a test environment. I’ve borrowed Jeffery Hicks’ disclaimer, because it simply says it all:

DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.

I’ve set the scripts to a max height as to not flood the page, but rest assured, everything’s there. Please do note that functions might refer to other functions, this is intended as a complete toolset, not just 1 piece.

If you have questions on the techniques used or suggestions on how to improve something, please let me know in the comment section!

function Get-LabSwitch {
#requires -Modules Hyper-V
#requires -RunAsAdministrator

<#

	.SYNOPSIS
		Checks the system for the availability of VM Lab Hyper-V switches.

	.DESCRIPTION
		Checks the system for the availability of VM Lab Hyper-V switches.
        This will check on either a single switch or all possible Hyper-V switches.

	.PARAMETER SwitchType
		Provide which switch to check for.
        Switches to chose from are Internal, External, Private or All [which will check all 3].
        Default naming standard of switches is VMLab-<SwitchType>

	.EXAMPLE
				PS C:\> Get-LabSwitch -SwitchType Internal

				Checks to see if the Internal Hyper-V switch for the VM Lab is available.

	.EXAMPLE
				PS C:\> Get-LabSwitch -SwitchType All

				Checks to see if all Hyper-V switches for the VM Lab are available.

	.NOTES

    Created by: Robert Prüst
    Blog: http://powershellpr0mpt.com
    Version: 1.0
    Module: PSP-VMLab

#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Internal','External','Private','All')]
        [string]$SwitchType
    )
    begin {
        Write-Verbose "Starting $($MyInvocation.MyCommand)"
        Write-Verbose 'Declaring variables'
        $Internal = $false
        $External = $false
        $Private = $false

    }
    process {
        switch ($SwitchType) {
            'Internal' {$Internal =$true}
            'External' {$External = $true}
            'Private' {$Private = $true}
            'All' {$Internal = $true ; $External = $true ; $Private = $true}
        }

        if ($Internal) {
            Write-Verbose 'Checking for Internal switch'
            try {
                Get-VMSwitch -Name 'VMLab-Internal' -SwitchType Internal -ErrorAction Stop | Out-Null
                Write-Output 'VM Lab Internal switch is available'
            } catch {
                Write-Output 'Unable to find Internal VM Lab switch'
            }

        }

        if ($External) {
            Write-Verbose 'Checking for External switch'
            try {
                Get-VMSwitch -Name 'VMLab-External' -SwitchType External -ErrorAction Stop | Out-Null
                Write-Output 'VM Lab External switch is available'
            } catch {
                Write-Output 'Unable to find External VM Lab switch'
            }

        }

        if ($Private) {
            Write-Verbose 'Checking for Private switch'
            try {
                Get-VMSwitch -Name 'VMLab-Private' -SwitchType Private -ErrorAction Stop | Out-Null
                Write-Output 'VM Lab Private switch is available'
            } catch {
                Write-Output 'Unable to find Private VM Lab switch'
            }

        }

    }

}

```


## New-LabSwitch

function New-LabSwitch {

#requires -Modules Hyper-V
#requires -RunAsAdministrator
#requires -Version 3.0

<#

	.SYNOPSIS
		Creates new VM Lab Hyper-V switches.

	.DESCRIPTION
		Creates new VM Lab Hyper-V switches.
        This will create either a single switch or all possible Hyper-V switches for the VM Lab.

	.PARAMETER SwitchType
		Provide which switch to create.
        Switches to chose from are Internal, External, Private or All [which will try and create all 3].
        Default naming standard of switches is VMLab-<SwitchType>

	.EXAMPLE
				PS C:\> New-LabSwitch -SwitchType Internal

				Creates a new Internal Hyper-V switch for the VM Lab.

	.EXAMPLE
				PS C:\> New-LabSwitch -SwitchType All

				Tries to create all Hyper-V switches for the VM Lab.

	.NOTES

    Created by: Robert Prüst
    Blog: http://powershellpr0mpt.com
    Version: 1.0
    Module: PSP-VMLab

#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Internal','External','Private','All')]
        [string]$SwitchType
    )
    begin {
        Write-Verbose "Starting $($MyInvocation.MyCommand)"
        Write-Verbose 'Declaring variables'
        $Internal = $false
        $External = $false
        $Private = $false

    }
    process {
        switch ($SwitchType) {
            'Internal' {$Internal =$true}
            'External' {$External = $true}
            'Private' {$Private = $true}
            'All' {$Internal = $true ; $External = $true ; $Private = $true}
        }

        if ($Internal) {
            if ((Get-LabSwitch -SwitchType Internal) -eq 'Unable to find Internal VM Lab switch'){
                Write-Verbose 'Creating Internal VM Lab switch'
                New-VMSwitch -Name 'VMLab-Internal' -SwitchType Internal -Notes 'VMLab-Internal'
            } else {
                Write-Output 'Internal VM Lab switch already exists'
            }
        }

        if ($External) {
            if ((Get-LabSwitch -SwitchType External) -eq 'Unable to find External VM Lab switch'){
                Write-Verbose 'Creating External VM Lab switch'
                New-VMSwitch -Name 'VMLab-External' -NetAdapterName ((Get-NetAdapter -Physical)[0].Name) -AllowManagementOS $true -Notes 'VMLab-External'
            } else {
                Write-Output 'External VM Lab switch already exists'
            }
        }

        if ($Private) {
            if ((Get-LabSwitch -SwitchType Private) -eq 'Unable to find Private VM Lab switch'){
                Write-Verbose 'Creating Private VM Lab switch'
                New-VMSwitch -Name 'VMLab-Private' -SwitchType Private -Notes 'VMLab-Private'
            } else {
                Write-Output 'Private VM Lab switch already exists'
            }
        }
    }

}

```


## Remove-LabSwitch

function Remove-LabSwitch {

#requires -Modules Hyper-V
#requires -RunAsAdministrator
#requires -Version 3.0

<#

	.SYNOPSIS
		Removes VM Lab Hyper-V switches.

	.DESCRIPTION
		Removes VM Lab Hyper-V switches.
        This will remove either a single switch or all possible Hyper-V switches for the VM Lab.

	.PARAMETER SwitchType
		Provide which switch to remove.
        Switches to chose from are Internal, External, Private or All [which will try and remove all 3].
        Default naming standard of switches is VMLab-<SwitchType>

	.EXAMPLE
				PS C:\> Remove-LabSwitch -SwitchType Internal

				Removes a new Internal Hyper-V switch for the VM Lab.

	.EXAMPLE
				PS C:\> Remove-LabSwitch -SwitchType All

				Tries to remove all Hyper-V switches for the VM Lab.

	.NOTES

    Created by: Robert Prüst
    Blog: http://powershellpr0mpt.com
    Version: 1.0
    Module: PSP-VMLab

#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Internal','External','Private','All')]
        [string]$SwitchType
    )
    begin {
        Write-Verbose "Starting $($MyInvocation.MyCommand)"
        Write-Verbose 'Declaring variables'
        $Internal = $false
        $External = $false
        $Private = $false

    }
    process {
        switch ($SwitchType) {
            'Internal' {$Internal =$true}
            'External' {$External = $true}
            'Private' {$Private = $true}
            'All' {$Internal = $true ; $External = $true ; $Private = $true}
        }

        if ($Internal) {
            if ((Get-LabSwitch -SwitchType Internal) -eq 'VM Lab Internal switch is available'){
                Write-Verbose 'Removing Internal VM Lab switch'
                Remove-VMSwitch -Name 'VMLab-Internal'
            } else {
                Write-Output "Internal VM Lab switch doesn't exist"
            }
        }

        if ($External) {
            if ((Get-LabSwitch -SwitchType External) -eq 'VM Lab External switch is available'){
                Write-Verbose 'Removing External VM Lab switch'
                Remove-VMSwitch -Name 'VMLab-External'
            } else {
                Write-Output "External VM Lab switch doesn't exist"
            }
        }

        if ($Private) {
            if ((Get-LabSwitch -SwitchType Private) -eq 'VM Lab Private switch is available'){
                Write-Verbose 'Removing Private VM Lab switch'
                Remove-VMSwitch -Name 'VMLab-Private'
            } else {
                Write-Output "Private VM Lab switch doesn't exist"
            }
        }
    }

}
```