Skip to content

Instantly share code, notes, and snippets.

@JohanSelmosson
Last active December 5, 2024 18:23
Show Gist options
  • Save JohanSelmosson/5211c59aed035858b149b34cae78974c to your computer and use it in GitHub Desktop.
Save JohanSelmosson/5211c59aed035858b149b34cae78974c to your computer and use it in GitHub Desktop.
function Set-DhcpScopeSettings {
<#
.SYNOPSIS
Modifies DHCP scope settings including lease duration, DNS settings, and DNS domain for specified scopes.
.DESCRIPTION
This function allows bulk modification of DHCP scope settings on a specified DHCP server.
It can modify:
- Lease duration
- DNS servers
- DNS domain
- DNS dynamic update settings
- PTR record handling
- DNS record cleanup settings
All changes are tracked and returned as PowerShell objects for further processing or logging.
.PARAMETER DhcpServer
The name of the DHCP server to modify. Defaults to local computer.
.PARAMETER ScopeId
One or more scope IDs to modify. If not specified, all scopes will be processed.
.PARAMETER ExcludeScopeId
One or more scope IDs to exclude from processing.
.PARAMETER LeaseDurationMinutes
The new lease duration in minutes. Valid range: 1-999999.
.PARAMETER DnsServers
An array of DNS server IP addresses to set for the scopes.
.PARAMETER ClearDnsSettings
Switch to clear all DNS server settings from the scopes.
.PARAMETER DnsDomain
The DNS domain name to set for the scopes.
.PARAMETER ClearDnsDomain
Switch to clear the DNS domain setting from the scopes.
.PARAMETER SkipDnsValidation
Switch to skip DNS server validation when setting Option 6.
.PARAMETER DnsUpdateSetting
Specifies how DNS records are updated. Valid values: 'Never', 'OnClientRequest', 'Always'.
.PARAMETER RegisterPtrRecords
Switch to enable or disable PTR record registration for DHCP clients.
.PARAMETER DiscardRecordsOnExpiry
Switch to enable or disable DNS record cleanup when leases expire.
.PARAMETER OverrideClientRequest
Switch to enable or disable overriding client DNS update requests.
.PARAMETER Force
Switch to bypass the confirmation prompt before making changes.
.EXAMPLE
Set-DhcpScopeSettings -DhcpServer "dhcp01" -LeaseDurationMinutes 1440
Sets lease duration to 24 hours for all scopes on dhcp01.
.EXAMPLE
Set-DhcpScopeSettings -ScopeId "192.168.1.0" -DnsServers "10.0.0.1","10.0.0.2" -Force
Updates DNS servers for a specific scope without confirmation prompt.
.EXAMPLE
Set-DhcpScopeSettings -ExcludeScopeId "10.0.0.0" -RegisterPtrRecords:$false
Disables PTR record registration for all scopes except 10.0.0.0.
.EXAMPLE
Set-DhcpScopeSettings -DnsUpdateSetting OnClientRequest -DiscardRecordsOnExpiry
Sets DNS update behavior to client-initiated and enables record cleanup on lease expiry.
.NOTES
Author: Johan Selmosson
Version: 2.0
Updated: 2024-12-05
Requirements:
- Windows DHCP Server PowerShell module
- Administrative privileges on the DHCP server
#>
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
param (
[Parameter(Mandatory = $false, Position = 0)]
[string]$DhcpServer = $env:COMPUTERNAME,
[Parameter(Mandatory = $false, Position = 1)]
[string[]]$ScopeId,
[Parameter(Mandatory = $false)]
[string[]]$ExcludeScopeId,
[Parameter(Mandatory = $false, Position = 2)]
[ValidateRange(1, 999999)]
[int]$LeaseDurationMinutes,
[Parameter(Mandatory = $false)]
[string[]]$DnsServers,
[Parameter(Mandatory = $false)]
[switch]$ClearDnsSettings,
[Parameter(Mandatory = $false)]
[string]$DnsDomain,
[Parameter(Mandatory = $false)]
[switch]$ClearDnsDomain,
[Parameter(Mandatory = $false)]
[switch]$SkipDnsValidation,
[Parameter(Mandatory = $false)]
[ValidateSet('Never', 'OnClientRequest', 'Always')]
[string]$DnsUpdateSetting,
[Parameter(Mandatory = $false)]
[switch]$RegisterPtrRecords,
[Parameter(Mandatory = $false)]
[switch]$DiscardRecordsOnExpiry,
[Parameter(Mandatory = $false)]
[switch]$OverrideClientRequest,
[Parameter(Mandatory = $false)]
[switch]$Force
)
begin {
$script:plannedChanges = @()
$script:changes = @()
}
process {
try {
Write-Host "`nStarting DHCP configuration update on server: " -NoNewline
Write-Host $DhcpServer -ForegroundColor Cyan
# Get scopes based on parameter
$scopes = if ($ScopeId) {
$ScopeId | ForEach-Object {
Get-DhcpServerv4Scope -ComputerName $DhcpServer -ScopeId $_ -ErrorAction Stop
}
}
else {
Get-DhcpServerv4Scope -ComputerName $DhcpServer
}
# Exclude specified scopes
if ($ExcludeScopeId) {
$scopes = $scopes | Where-Object { $ExcludeScopeId -notcontains $_.ScopeId }
}
Write-Host "`nFound" -NoNewline
Write-Host " $($scopes.Count) " -ForegroundColor Yellow -NoNewline
Write-Host "scopes to process`n"
foreach ($scope in $scopes) {
# Get current settings
$currentScope = Get-DhcpServerv4Scope -ComputerName $DhcpServer -ScopeId $scope.ScopeId
$currentLeaseMinutes = $currentScope.LeaseDuration.TotalMinutes
$currentDnsServers = (Get-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 6 -ErrorAction SilentlyContinue).Value
$currentDnsDomain = (Get-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 15 -ErrorAction SilentlyContinue).Value -join ", "
$currentDnsSettings = Get-DhcpServerv4DnsSetting -ComputerName $DhcpServer -ScopeId $scope.ScopeId
# Check Lease Duration
if ($PSBoundParameters.ContainsKey('LeaseDurationMinutes') -and ($currentLeaseMinutes -ne $LeaseDurationMinutes)) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'Lease Duration'
Current = "$currentLeaseMinutes minutes"
New = "$LeaseDurationMinutes minutes"
}
}
# Check DNS Servers
if ($ClearDnsSettings -and $currentDnsServers) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'DNS Servers'
Current = $currentDnsServers -join ', '
New = 'Cleared'
}
}
elseif ($DnsServers) {
$currentDnsString = $currentDnsServers -join ', '
$newDnsString = $DnsServers -join ', '
if ($currentDnsString -ne $newDnsString) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'DNS Servers'
Current = if ($currentDnsString) { $currentDnsString } else { 'Not set' }
New = $newDnsString
}
}
}
# Check DNS Domain
if ($ClearDnsDomain -and $currentDnsDomain) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'DNS Domain'
Current = $currentDnsDomain
New = 'Cleared'
}
}
elseif ($DnsDomain -and $currentDnsDomain -ne $DnsDomain) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'DNS Domain'
Current = if ($currentDnsDomain) { $currentDnsDomain } else { 'Not set' }
New = $DnsDomain
}
}
# Check DNS Update Settings
if ($PSBoundParameters.ContainsKey('DnsUpdateSetting') -and
$currentDnsSettings.DynamicUpdates -ne $DnsUpdateSetting) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'DNS Update Setting'
Current = $currentDnsSettings.DynamicUpdates
New = $DnsUpdateSetting
}
}
# Check PTR Records setting
if ($PSBoundParameters.ContainsKey('RegisterPtrRecords') -and
$currentDnsSettings.UpdateDnsRRForOlderClients -ne $RegisterPtrRecords) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'Register PTR Records'
Current = $currentDnsSettings.UpdateDnsRRForOlderClients
New = $RegisterPtrRecords
}
}
# Check Discard Records setting
if ($PSBoundParameters.ContainsKey('DiscardRecordsOnExpiry') -and
$currentDnsSettings.DeleteDnsRROnLeaseExpiry -ne $DiscardRecordsOnExpiry) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'Discard Records on Expiry'
Current = $currentDnsSettings.DeleteDnsRROnLeaseExpiry
New = $DiscardRecordsOnExpiry
}
}
# Check Override Client Request setting
if ($PSBoundParameters.ContainsKey('OverrideClientRequest') -and
$currentDnsSettings.DisableDnsPtrRRUpdate -ne $OverrideClientRequest) {
$script:plannedChanges += [PSCustomObject]@{
Scope = $scope.ScopeId
Setting = 'Override Client Request'
Current = $currentDnsSettings.DisableDnsPtrRRUpdate
New = $OverrideClientRequest
}
}
}
# If there are changes, show them and process if confirmed
if ($script:plannedChanges.Count -gt 0) {
Write-Host "`nPlanned changes:" -ForegroundColor Yellow
$script:plannedChanges | Format-Table -AutoSize | Out-Host
if (-not $PSCmdlet.ShouldProcess("Perform changes")) {
return
}
# Skip confirmation if -Force is used
if (-not $Force) {
$title = "Confirm Changes"
$question = "Do you want to proceed with these changes?"
$choices = "&Yes", "&No"
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 1) {
Write-Host "`nOperation cancelled by user" -ForegroundColor Yellow
return
}
}
foreach ($scope in $scopes) {
Write-Host "----------------------------------------" -ForegroundColor Blue
Write-Host "Scope: " -NoNewline
Write-Host "$($scope.ScopeId) ($($scope.Name))" -ForegroundColor Yellow
Write-Host "----------------------------------------" -ForegroundColor Blue
# Update Lease Duration
if ($PSBoundParameters.ContainsKey('LeaseDurationMinutes')) {
$currentScope = Get-DhcpServerv4Scope -ComputerName $DhcpServer -ScopeId $scope.ScopeId
$currentLeaseMinutes = $currentScope.LeaseDuration.TotalMinutes
if ($currentLeaseMinutes -ne $LeaseDurationMinutes) {
Write-Host "Lease Duration"
Write-Host "Current: " -NoNewline
Write-Host "$currentLeaseMinutes minutes" -ForegroundColor Gray
Write-Host "New : " -NoNewline
Write-Host "$LeaseDurationMinutes minutes" -ForegroundColor Green
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Set lease duration to $LeaseDurationMinutes minutes")) {
Set-DhcpServerv4Scope -ComputerName $DhcpServer -ScopeId $scope.ScopeId -LeaseDuration (New-TimeSpan -Minutes $LeaseDurationMinutes)
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'LeaseDuration'
OldValue = $currentLeaseMinutes
NewValue = $LeaseDurationMinutes
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
}
}
# Update DNS Servers
$currentDnsServers = (Get-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 6 -ErrorAction SilentlyContinue).Value
Write-Host "`nDNS Servers"
Write-Host "Current: " -NoNewline
Write-Host "$(if ($currentDnsServers) { $currentDnsServers -join ', ' } else { 'Not set' })" -ForegroundColor Gray
if ($ClearDnsSettings -and $currentDnsServers) {
Write-Host "New : " -NoNewline
Write-Host "Clearing DNS servers" -ForegroundColor Yellow
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Clear DNS servers")) {
Remove-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 6
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'ClearDnsServers'
OldValue = $currentDnsServers -join ','
NewValue = $null
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
}
elseif ($DnsServers) {
$currentDnsString = $currentDnsServers -join ', '
$newDnsString = $DnsServers -join ', '
if ($currentDnsString -ne $newDnsString) {
Write-Host "New : " -NoNewline
Write-Host "$newDnsString" -ForegroundColor Green
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Set DNS servers to: $newDnsString")) {
$dnsParams = @{
ComputerName = $DhcpServer
ScopeId = $scope.ScopeId
OptionId = 6
Value = $DnsServers
}
if ($SkipDnsValidation) {
$dnsParams.Add('Force', $true)
}
Set-DhcpServerv4OptionValue @dnsParams
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'SetDnsServers'
OldValue = $currentDnsString
NewValue = $newDnsString
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
}
}
# Update DNS Domain
$currentDnsDomain = (Get-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 15 -ErrorAction SilentlyContinue).Value
Write-Host "`nDNS Domain"
Write-Host "Current: " -NoNewline
Write-Host "$(if ($currentDnsDomain) { $currentDnsDomain } else { 'Not set' })" -ForegroundColor Gray
if ($ClearDnsDomain -and $currentDnsDomain) {
Write-Host "New : " -NoNewline
Write-Host "Clearing DNS domain" -ForegroundColor Yellow
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Clear DNS domain")) {
Remove-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 15
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'ClearDnsDomain'
OldValue = $currentDnsDomain
NewValue = $null
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
}
elseif ($DnsDomain -and $currentDnsDomain -ne $DnsDomain) {
Write-Host "New : " -NoNewline
Write-Host "$DnsDomain" -ForegroundColor Green
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Set DNS domain to: $DnsDomain")) {
Set-DhcpServerv4OptionValue -ComputerName $DhcpServer -ScopeId $scope.ScopeId -OptionId 15 -Value $DnsDomain
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'SetDnsDomain'
OldValue = $currentDnsDomain
NewValue = $DnsDomain
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
}
# Handle DNS Settings
$currentDnsSettings = Get-DhcpServerv4DnsSetting -ComputerName $DhcpServer -ScopeId $scope.ScopeId
$dnsSettingsChanged = $false
$dnsParams = @{
ComputerName = $DhcpServer
ScopeId = $scope.ScopeId
}
Write-Host "`nDNS Settings"
Write-Host "Current settings:"
Write-Host "- DNS Updates: " -NoNewline
Write-Host $currentDnsSettings.DynamicUpdates -ForegroundColor Gray
Write-Host "- Register PTR: " -NoNewline
Write-Host $currentDnsSettings.UpdateDnsRRForOlderClients -ForegroundColor Gray
Write-Host "- Discard on Expiry: " -NoNewline
Write-Host $currentDnsSettings.DeleteDnsRROnLeaseExpiry -ForegroundColor Gray
Write-Host "- Override Client: " -NoNewline
Write-Host $currentDnsSettings.DisableDnsPtrRRUpdate -ForegroundColor Gray
if ($PSBoundParameters.ContainsKey('DnsUpdateSetting')) {
$dnsParams['DynamicUpdates'] = $DnsUpdateSetting
$dnsSettingsChanged = $true
}
if ($PSBoundParameters.ContainsKey('RegisterPtrRecords')) {
$dnsParams['UpdateDnsRRForOlderClients'] = $RegisterPtrRecords.IsPresent
$dnsSettingsChanged = $true
}
if ($PSBoundParameters.ContainsKey('DiscardRecordsOnExpiry')) {
$dnsParams['DeleteDnsRROnLeaseExpiry'] = $DiscardRecordsOnExpiry.IsPresent
$dnsSettingsChanged = $true
}
if ($PSBoundParameters.ContainsKey('OverrideClientRequest')) {
$dnsParams['DisableDnsPtrRRUpdate'] = $OverrideClientRequest.IsPresent
$dnsSettingsChanged = $true
}
if ($dnsSettingsChanged) {
Write-Host "`nApplying new DNS settings..." -ForegroundColor Yellow
if ($PSCmdlet.ShouldProcess($scope.ScopeId, "Update DNS settings")) {
Set-DhcpServerv4DnsSetting @dnsParams
# Get updated settings for verification and output
$newDnsSettings = Get-DhcpServerv4DnsSetting -ComputerName $DhcpServer -ScopeId $scope.ScopeId
# Compare and create individual records for each changed setting
if ($PSBoundParameters.ContainsKey('DnsUpdateSetting') -and
$currentDnsSettings.DynamicUpdates -ne $newDnsSettings.DynamicUpdates) {
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'DynamicUpdates'
OldValue = $currentDnsSettings.DynamicUpdates
NewValue = $newDnsSettings.DynamicUpdates
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
if ($PSBoundParameters.ContainsKey('RegisterPtrRecords') -and
$currentDnsSettings.UpdateDnsRRForOlderClients -ne $newDnsSettings.UpdateDnsRRForOlderClients) {
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'RegisterPtrRecords'
OldValue = $currentDnsSettings.UpdateDnsRRForOlderClients
NewValue = $newDnsSettings.UpdateDnsRRForOlderClients
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
if ($PSBoundParameters.ContainsKey('DiscardRecordsOnExpiry') -and
$currentDnsSettings.DeleteDnsRROnLeaseExpiry -ne $newDnsSettings.DeleteDnsRROnLeaseExpiry) {
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'DiscardRecordsOnExpiry'
OldValue = $currentDnsSettings.DeleteDnsRROnLeaseExpiry
NewValue = $newDnsSettings.DeleteDnsRROnLeaseExpiry
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
if ($PSBoundParameters.ContainsKey('OverrideClientRequest') -and
$currentDnsSettings.DisableDnsPtrRRUpdate -ne $newDnsSettings.DisableDnsPtrRRUpdate) {
$script:changes += [PSCustomObject]@{
ScopeId = $scope.ScopeId
ScopeName = $scope.Name
ChangeType = 'OverrideClientRequest'
OldValue = $currentDnsSettings.DisableDnsPtrRRUpdate
NewValue = $newDnsSettings.DisableDnsPtrRRUpdate
TimeStamp = (Get-Date)
ServerName = $DhcpServer
Description = $scope.Description
}
}
Write-Host "New settings applied:" -ForegroundColor Green
Write-Host "- DNS Updates: " -NoNewline
Write-Host $newDnsSettings.DynamicUpdates -ForegroundColor Green
Write-Host "- Register PTR: " -NoNewline
Write-Host $newDnsSettings.UpdateDnsRRForOlderClients -ForegroundColor Green
Write-Host "- Discard on Expiry: " -NoNewline
Write-Host $newDnsSettings.DeleteDnsRROnLeaseExpiry -ForegroundColor Green
Write-Host "- Override Client: " -NoNewline
Write-Host $newDnsSettings.DisableDnsPtrRRUpdate -ForegroundColor Green
}
}
Write-Host "----------------------------------------" -ForegroundColor Blue
Write-Host ""
}
Write-Host "`nConfiguration update completed successfully!`n" -ForegroundColor Green
}
else {
Write-Host "`nNo changes required" -ForegroundColor Green
}
}
catch {
Write-Host "`nError occurred: " -ForegroundColor Red -NoNewline
Write-Host "$_`n" -ForegroundColor Red
throw $_
}
}
end {
if ($script:changes.Count -gt 0) {
$script:changes
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment