Hyper-V Windows Server 2019 Windows Server 2022

Create a Hyper-V VM to run pfSense with a PowerShell script


In this blog post, you’ll learn how to use a PowerShell script to create a Hyper-V virtual machine (VM) to run the open-source firewall and routing software pfSense.

In my on-premises virtual lab, which runs on Hyper-V, I use pfSense* as the primary perimeter firewall solution.

*If you are interested, you can find additional information about pfSense over here.


To automate the deployment process of a Hyper-V VM (Generation 2) to run pfSense, I wrote the following PowerShell script. This script includes the following steps and configurations:

  • Create the VM (generation 2, static memory) if it does not already exist.
  • Configure the VM (with 1 vCPU and VM notes configured).
  • Disable Secure Boot.
  • Add a second Network adapter.
  • Create the Virtual Hard Disk folder.
  • Create a virtual disk (.vhdx) and attach it to the VM.
  • Disable VM Checkpoints for the Hyper-V VM (because, for me, it runs in my POC Demo environment).
  • Add information to the VM Notes field.


To use the script, copy and save it as Create-Hyper-V-VM-to-run-pfSense.ps1 or download it from GitHub. Then, before using the script, adjust all variables to your needs, and then run the customized script from Windows PowerShell on your Hyper-V host.


Prerequisites

  • A Hyper-V host running Windows Server 2019 or 2022.
  • Two Hyper-V virtual switches, one for your internal LAN connections (Private) and the other for your WAN connections (External).
  • Change all the variables in the script where needed to fit your needs (you can find an adjusted example in one of the screenshots below).





PowerShell script

Logon to your Hyper-V host with an administrator account and then run the script with the required parameters:

.\Create-Hyper-V-VM-to-run-pfSense.ps1 -VMName <"your VMName name here">



<#
.SYNOPSIS

A script used to create a Hyper-V VM for running pfSense.

.DESCRIPTION

A script used to create a Hyper-V VM for running pfSense.
This script will do all of the following:

Create the VM (generation 2, static memory) if it does not already exist.
Configure the VM (with 1 vCPU, checkpoints disabled (because for me it runs in my POC Demo environment), and VM notes configured).
Add a second Network adapter.
Create the Virtual Hard Disk folder.
Create a virtual disk (.vhdx) and attach it to the VM.
Disable VM Checkpoints for the Hyper-V virtual machine.
Add information to the VM Notes field.

.NOTES

Filename:       Create-Hyper-V-VM-to-run-pfSense.ps1
Created:        02/08/2023
Last modified:  02/08/2023
Author:         Wim Matthyssen
Version:        1.0
PowerShell:     Windows PowerShell
Requires:       PowerShell (v5.1)
Action:         Change variables were needed to fit your needs. 
Disclaimer:     This script is provided "as is" with no warranties.

.EXAMPLE

Run on Hyper-V host
.\Create-Hyper-V-VM-to-run-pfSense.ps1 -VMName <"your VMName name here"> 

-> .\Create-Hyper-V-VM-to-run-pfSense.ps1 -VMName slpfw001

.LINK

https://wmatthyssen.com/2023/08/03/create-a-hyper-v-vm-to-run-pfsense-with-a-powershell-script/
#>

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Parameters

param(
    # $vmName -> Name of Hyper-V VM
    [parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] [string] $vmName
    )

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Variables

$vmLoc = #<your VM files location here> Location where the VM files will be stored. Example: "F:\VMs\" 
$networkSwitch1 = #<your LAN Network Switch name here> Name of the Network Switch (LAN). Example: "vSwitch-Private" 
$networkSwitch2 = #<your WAN Network Switch name here> Name of the Network Switch (WAN). Example: "vSwitch-External"
$vhdxFolder = #<your virtual hard disks folder name here> The name of the virtual hard disks folder. Example: "Virtual Hard Disks"
$vmNotes = #<your VM notes here> The VM notes here. Example: "Role: pfSense Firewall"+"`r`n"+"VM Generation: $vmGen"

$vmGen = "2" # VM Generation
$vmRamStatic = 1GB # Static memory assigned to the VM
$vCPU = 1 # Number of virtual CPUs
$automaticStartAction = "StartIfRunning" # Action that is run when the Hyper-V service is starting (Nothing, Start, StartIfRunning)
$automaticStartDelay = 60 # Number of seconds to wait before the automatic start action is run
$automaticStopAction = "Save" # Action that is run when the Hyper-V service is stopping
$vmLocFull = $vmLoc + $vmName
$vhdxDrive = $vmName + "-1" + ".vhdx"
$vhdxLocation = $vmLoc + $vmName + "\" + $vhdxFolder + "\"  + $vhdxDrive
$diskSize = 2GB                           

Set-PSBreakpoint -Variable currenttime -Mode Read -Action {$global:currenttime = Get-Date -Format "dddd MM/dd/yyyy HH:mm"} | Out-Null 
$foregroundColor1 = "Green"
$foregroundColor2 = "Yellow"
$foregroundColor3 = "Red"
$writeEmptyLine = "`n"
$writeSeperatorSpaces = " - "

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script started

Write-Host ($writeEmptyLine + "# Script started. Without errors, it can take up to 1 minute to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create the VM (generation 2, static memory) if it does not already exist

try {
    Get-VM -Name $vmName -ErrorAction Stop
    Write-Host ($writeEmptyLine + "# VM $vmName already exists, please validate" + $writeSeperatorSpaces + $currentTime)`
    -foregroundcolor $foregroundColor3 $writeEmptyLine
    Start-Sleep -s 3
    Write-Host -NoNewLine ("# Press any key to exit the script ..." + $writeEmptyLine)`
    -foregroundcolor $foregroundColor1 $writeEmptyLine;
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null;
    return 
} catch {
    New-VM -Name $vmName `
    -Path $vmLoc `
    -NoVHD `
    -Generation $vmGen `
    -MemoryStartupBytes $vmRamStatic `
    -SwitchName $networkSwitch1 | Out-Null 
}

Write-Host ($writeEmptyLine + "# VM $vmName is created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Configure the VM (with 1 vCPU, checkpoints disabled (because for me it runs in my POC Demo environment), and VM notes configured)

Set-VM -Name $vmName `
    -ProcessorCount $vCPU `
    -AutomaticStartAction $automaticStartAction `
    -AutomaticStartDelay $automaticStartDelay `
    -AutomaticStopAction $automaticStopAction `
    -AutomaticCheckpointsEnabled $false | Out-Null 

Write-Host ($writeEmptyLine + "# VM $vmName is created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Disable Secure Boot

Set-VMFirmware -VMName $vmName -EnableSecureBoot Off

Write-Host ($writeEmptyLine + "# Secure Boot disabled" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Add a second Network Adapter

Add-VMNetworkAdapter -VMName $vmName -SwitchName $networkSwitch2 | Out-Null

Write-Host ($writeEmptyLine + "# Second Network Adaptor added and connected to virtual switch $networkSwitch2" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create Virtual Hard Disk folder

New-Item -Path $vmLocFull -Name $vhdxFolder -ItemType "directory" | Out-Null

Write-Host ($writeEmptyLine + "# Virtual Hard Disk folder created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create a virtual disk (.vhdx) and attach it to the VM

# Create .vhdx
New-VHD -SizeBytes $diskSize -Path $vhdxLocation | Out-Null

# Attach .vhdx
Add-VMHardDiskDrive -VMName $vmName -Path $vhdxLocation -ControllerType SCSI -ControllerNumber 0 | Out-Null

Write-Host ($writeEmptyLine + "# New .vhdx created an attached to VM $vmName" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Disable VM Checkpoints for the Hyper-V virtual machine

Set-VM -Name $vmName -CheckpointType Disabled | Out-Null

Write-Host ($writeEmptyLine + "# Checkpoints disabled" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Add information to the VM Notes field

Set-VM -Name $vmName -Notes "$($vm.Notes)$vmNotes" -Confirm:$false | Out-Null

Write-Host ($writeEmptyLine + "# Info added into the VM Notes" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script completed

Write-Host ($writeEmptyLine + "# Script completed" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------











For additional configuration of pfSense running within your Hyper-V VM, you can follow this step-by-step guide provided at the following link


Conclusion

pfSense is a free, customized distribution of FreeBSD that can turn a VM into a full-featured router and firewall. Its user-friendly installation and maintenance processes through a web-based interface make it a good firewall solution for your home or virtual lab.

I hope the PowerShell script is useful for you and provides you with a good starting point for implementing pfSense in your on-premises environment.

Should you have any questions or suggestions regarding the script, feel free to reach out to me through my Twitter handle (@wmatthyssen) or simply leave a comment, and I’ll be more than happy to assist.


Wim is an Azure Technical Advisor and Trainer with over fifteen years of Microsoft technology experience. As a Microsoft Certified Trainer (MCT), his strength is assisting companies in the transformation of their businesses to the Cloud by implementing the latest features, services, and solutions. Currently, his main focus is on the Microsoft Hybrid Cloud Platform, and especially on Microsoft Azure and the Azure hybrid services.   Wim is also a Microsoft MVP in the Azure category and a founding board member of the MC2MC user group. As a passionate community member, he regularly writes blogs and speaks about his daily experiences with Azure and other Microsoft technologies.

2 comments on “Create a Hyper-V VM to run pfSense with a PowerShell script

  1. Pingback: How to install and configure pfSense within a Hyper-V VM – Wim Matthyssen

  2. Pingback: How to configure advanced settings for pfSense running within a Hyper-V VM – Wim Matthyssen

Leave a comment