Public/DomainManagement/Update-PiHoleDomain.ps1
|
function Update-PiHoleDomain { <# .SYNOPSIS Update a domain .DESCRIPTION Updates an existing domain's Comment, Group(s), and/or Enabled state. The underlying Pi-hole API replaces the entire domain entry on update, so any property you don't pass here is preserved by first reading the domain's current value and resending it - nothing is silently cleared just because you only meant to change one property. Note: the Pi-hole API documents moving a domain to a different -Type/-Kind by including those fields in this same PUT request, but real-world testing against a live server showed this leaves a stale duplicate at the original type/kind rather than actually moving it. This function only ever updates Comment, Group, and Enabled in place; to change a domain's Type or Kind, remove it with Remove-PiHoleDomain and add it again with New-PiHoleDomain. .PARAMETER PiHoleServer The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "http://192.168.1.100" .PARAMETER Password The API Password you generated from your PiHole server .PARAMETER Domain The domain to update .PARAMETER Type Whether this is an allowed or denied domain .PARAMETER Kind Whether -Domain is an exact match or a regular expression .PARAMETER Comment The new comment for the domain. Leave unset to keep the domain's current comment .PARAMETER Group The group(s) this domain should apply to. Leave unset to keep the domain's current group(s) .PARAMETER Enabled Whether the domain should be enabled. Leave unset to keep the domain's current state .PARAMETER IgnoreSsl Set to $true to skip SSL certificate validation .PARAMETER RawOutput This will dump the response instead of the formatted object .EXAMPLE Update-PiHoleDomain -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" -Domain "example.com" -Type Allow -Kind Exact -Enabled $false #> [CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#put-/domains/-type-/-kind-/-domain-')] [Diagnostics.CodeAnalysis.SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "", Justification = "Ignoring for now")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [Parameter(Mandatory = $true)] [string]$Domain, [Parameter(Mandatory = $true)] [ValidateSet("Allow", "Deny")] [string]$Type, [Parameter(Mandatory = $true)] [ValidateSet("Exact", "Regex")] [string]$Kind, [string]$Comment, [string[]]$Group, [Nullable[bool]]$Enabled, [bool]$IgnoreSsl = $false, [bool]$RawOutput = $false ) try { if (-not $PSBoundParameters.ContainsKey('Comment') -and -not $PSBoundParameters.ContainsKey('Group') -and -not $PSBoundParameters.ContainsKey('Enabled')) { throw "To update $Domain, you must specify the Comment, Group, and/or Enabled parameter" } $ExistingDomain = Get-PiHoleDomain -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl -Type $Type -Kind $Kind -Domain $Domain if (-not $ExistingDomain) { throw "Cannot find $Domain of type $Type/$Kind on $PiHoleServer! Please use New-PiHoleDomain to create it" } $AllGroups = Get-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl $GroupNamesToResolve = if ($PSBoundParameters.ContainsKey('Group')) { $Group } else { $ExistingDomain.Groups } $AllGroupsNames = @() $AllGroupsIds = @() foreach ($GroupItem in $GroupNamesToResolve) { $FoundGroup = $AllGroups | Where-Object { $_.Name -eq $GroupItem } if ($FoundGroup) { $AllGroupsNames += $FoundGroup.Name $AllGroupsIds += $FoundGroup.Id } else { throw "Cannot find $GroupItem on $PiHoleServer! Please use Get-PiHoleGroup to list all groups" } } $Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl # The API replaces the whole domain entry on update, so any property not explicitly # passed here is resent using the domain's current value to avoid silently clearing it. # Type/Kind are always resent as-is - see the .DESCRIPTION note on why this never moves # a domain to a different Type/Kind. $Body = @{ type = $Type.ToLower() kind = $Kind.ToLower() comment = if ($PSBoundParameters.ContainsKey('Comment')) { $Comment } else { $ExistingDomain.Comment } groups = [Object[]]($AllGroupsIds) enabled = if ($PSBoundParameters.ContainsKey('Enabled')) { $Enabled } else { $ExistingDomain.Enabled } } $Params = @{ Headers = @{sid = $($Sid) } Uri = "$($PiHoleServer.OriginalString)/api/domains/$($Type.ToLower())/$($Kind.ToLower())/$([System.Uri]::EscapeDataString($Domain))" Method = "Put" SkipCertificateCheck = $IgnoreSsl Body = $Body | ConvertTo-Json -Depth 10 ContentType = "application/json" } $Response = Invoke-RestMethod @Params if ($RawOutput) { Write-Output $Response } else { $ObjectFinal = foreach ($Item in $Response.domains) { [PSCustomObject]@{ Domain = $Item.domain Unicode = $Item.unicode Type = $Item.type.SubString(0, 1).ToUpper() + $Item.type.SubString(1).ToLower() Kind = $Item.kind.SubString(0, 1).ToUpper() + $Item.kind.SubString(1).ToLower() Comment = $Item.comment Groups = $AllGroupsNames Enabled = $Item.enabled Id = $Item.id DateAdded = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_added).LocalTime DateModified = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_modified).LocalTime } } Write-Output $ObjectFinal } } catch { Write-Error -Message $_.Exception.Message } finally { if ($Sid) { Remove-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Sid $Sid -IgnoreSsl $IgnoreSsl } } } |