
For a while, I’ve used Microsoft’s DHCP server in my home lab. Within the last year though, I’ve started having issues where my Unifi WAP’s would have trouble getting an IP address. If I rebooted the WAP’s, everything was fine. Because of this, I don’t really think its a problem with my DHCP server or configuration, but I wanted to be absolutely sure and rule it out.
I had a slight problem. Although I use DHCP, I use DHCP reservations for almost everything on my network. The only things I don’t reserve are guest devices. I have an excel spreadsheet that I maintain that has all my devices and their reservations. I needed a way to easily and automatically import these reservations into pfSense for when I make additions and/or changes, just like I do for Microsoft’s DHCP server currently.
I already have a powershell script to do this for Microsoft DHCP, so I used that to get started. It wasn’t as difficult as I thought it would be. A few lines of powershell later, and I have a working powershell script that takes my excel file and dumps it into pfSense’s DHCP configuration, then restarts the service.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | # 1) Install-Module ImportExcel -Scope CurrentUser # 2) Save this script in the same directory as your spreadsheet, or adjust the relevant lines Clear Set-Location $PSScriptRoot $excelFile = "Home Network.xlsx" # Prompt for credentials to login to pfsense # The only permission this user needs is "WebCfg - Diagnostics: Backup & Restore" # If you want the script to be able to restart the dhcp service, then you # also need: # Allow access to the 'Services: DHCP Server' page. # and # Allow access to the 'Status: Services' page. if ( $cred -eq $null ) { $cred = ( Get-Credential ) } # get csrf token for request $lastRequest = ( Invoke-WebRequest $pfSenseUrl /diag_backup.php -SessionVariable pfSenseSession) $csrf = $lastRequest .Forms.Fields[ "__csrf_magic" ] # login $bstr = [System.Runtime.InteropServices.Marshal] ::SecureStringToBSTR( $cred .Password) $postParams = @{login= 'Login' ;usernamefld= $cred .UserName;passwordfld=( [System.Runtime.InteropServices.Marshal] ::PtrToStringAuto( $bstr ));__csrf_magic= $csrf } $lastRequest = ( Invoke-WebRequest $pfSenseUrl /diag_backup.php -WebSession $pfSenseSession -Method Post -Body $postParams ) # get csrf token for next request $lastRequest = ( Invoke-WebRequest $pfSenseUrl /diag_backup.php -WebSession $pfSenseSession ) $csrf = $lastRequest .Forms.Fields[ "__csrf_magic" ] # download current dhcp server configuration $postParams = @{download= 'download' ;donotbackuprrd= 'yes' ;__csrf_magic= $csrf ;backuparea= 'dhcpd' ;} $lastRequest = ( Invoke-WebRequest $pfSenseUrl /diag_backup.php -WebSession $pfSenseSession -Method Post -Body $postParams ) #remove all current static mappings [System.Xml.XmlDocument] $xml = [System.Xml.XmlDocument] ::new() $xml .LoadXml( [System.Text.ASCIIEncoding] ::UTF8.GetString( $lastRequest .Content)) $xml .dhcpd.lan.SelectNodes( "staticmap" ) | ForEach-Object { [void] $_ .ParentNode.RemoveChild( $_ ) } $lastRequest = $null # convert the excel file to csv for easy manipulation in powershell Import-Excel $excelFile | Export-Csv -Path "./$($excelFile).csv" -NoTypeInformation # parse the generated csv file and add mappings to the xml document in memory Import-Csv "$($excelFile).csv" | ForEach-Object { $mac = $_ .UniqueID if ( $mac .Length -gt 0 ) { $desc = $_ .HostName if ( $_ .Description.Length -gt 0) { $desc = $_ .Description } if ( $r -eq $null ) { Write-Host Adding reservation for $_ $reservation = $xml .CreateElement( "staticmap" ) $macEle = $xml .CreateElement( "mac" ) $macEle .InnerText = $mac $descEle = $xml .CreateElement( "descr" ) $descEle .InnerText = $desc $ipEle = $xml .CreateElement( "ipaddr" ) $ipEle .InnerText = $_ .IP $hostEle = $xml .CreateElement( "hostname" ) $hostEle .InnerText = $_ .HostName [void] $reservation .AppendChild( $macEle ) [void] $reservation .AppendChild( $ipEle ) [void] $reservation .AppendChild( $hostEle ) [void] $reservation .AppendChild( $descEle ) [void] $xml .dhcpd.lan.AppendChild( $reservation ) } } } $LF = "`r`n" $boundary = [System.Guid] ::NewGuid().ToString() $contentType = "multipart/form-data; boundary=`"$boundary`"" # generate the multipart/form-data body with required form variables and the config " file " $bodyLines = ( " -- $boundary ", " Content-Disposition: form-data; name=` "__csrf_magic`"$LF" , $csrf , "--$boundary" , "Content-Disposition: form-data; name=`"restorearea`"$LF" , "dhcpd" , "--$boundary" , "Content-Disposition: form-data; name=`"conffile`"; filename=`"dhcpd.xml`"", " Content-Type: text/xml $LF ", $xml.OuterXml, " -- $boundary ", " Content-Disposition: form-data; name=` "restore`"$LF" , "Restore Configuration" ) -join $LF try { # restore the dhcpd configuration to pfSense $lastRequest = ( Invoke-WebRequest $pfSenseUrl /diag_backup.php -ContentType $contentType -WebSession $pfSenseSession -Method Post -Body $bodyLines -ErrorAction SilentlyContinue) } catch {} if ( $lastRequest .StatusCode -eq 200 ) { Write-Host Write-Host Success! -ForegroundColor Green Write-Host Write-Host Restarting DHCP service # get csrf token for request $csrf = $lastRequest .Forms.Fields[ "__csrf_magic" ] #restart dhcp service $postParams = @{ajax= 'ajax' ;mode= 'restartservice' ;__csrf_magic= $csrf ;service= 'dhcpd' ;} $lastRequest = ( Invoke-WebRequest $pfSenseUrl /status_services.php -Method Post -WebSession $pfSenseSession -Body $postParams ) } else { Write-Host Failure! -ForegroundColor Red } $bstr = $null $postParams = $null $lastRequest = $null |

11 comments on “Scripting pfSense DHCP static assignments”
fgfgfghey, I happened to find this script and I wanna use it to populate a bunch of DHCP static mappings on my newly configured PfSense install but before I run your script, can you post a screenshot (or the column headers) for your csv file? I assume it’s mac, descr, ipaddr, hostname but wanna be sure.
You wouldn’t believe how many people would find this useful.
thanks for writing it!
The columns that matter are:
HostName
Description
UniqueID
IP
They’re referenced in the script as properties on the automatic variable $_.
For example, $_.HostName, $.Description, $_.UniqueID, and $_.IP
The other columns are just columns I’m using for my own personal organization.
Glad it is helpful.
Sorry to bug you on this but I am getting an error. I am stepping through this with powershell ISE and
line 41 is giving me trouble.. producing the following error:
$lastRequest = $null
At line:1 char:14
+ $xml = ::new()
+ ~
An expression was expected after ‘(‘.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedExpression
It looks like your $xml declaration might be incorrect.
Try “[xml]$xml = [xml]::new()” instead of “$xml = ::new()”
That worked!
Thanks for your help!
I posted a link to your site and your blog post on the pfSense reddit.
https://www.reddit.com/r/PFSENSE/comments/j2s0ih/static_mapping_dhcp_reservation_in_pfsense_with/
Thanks for the reddit post.
After reading it, I went and checked my original post, and the syntax is correct in the post, but it appears that the syntax highlighter doesn’t like it and it’s getting removed there :/
Edit: Changed it from the shortcut [xml] to [System.Xml.XmlDocument] and it seems to have fixed the formatting.
Hello
to skip the ssl error i included
add-type @”
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
“@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
so it looks like this
$pfSenseUrl = “https://x.x.x.x”
$excelFile = “Home Network.xlsx”
add-type @”
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
“@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
what this dose it tells the script to trust all certs so the selfsigned cert will not complain
Hello
can you also make this work if you have multiple dns servers in pfsense for vlans?
like a sheet per vlan with just the vlan id or the name of the dhcp server
My pfSense setup is pretty basic and don’t have multiple vlans/dns servers. It still should be relatively easy since I’m just using a backup/restore process to do it. Can you send me a sample backup that contains just your dns area?
Hello
no idea how to do that..
can you tell me how to do it and il gladly do it
update: with the release of 22.01 it seems like this scrip is no longer working.
i get this error
:37 char:17
+ … tRequest = (Invoke-WebRequest $pfSenseUrl/diag_backup.php -SessionVar …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Cannot index into a null array.
At C:\Users\TS\Dokument\pfsense\pfsensenetworkimport.ps1:38 char:1
+ $csrf = $lastRequest.Forms.Fields[“__csrf_magic”]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray