Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion PiHoleShell/PiHoleShell.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ Export-ModuleMember -Function @(
#ListManagement
'Get-PiHoleList', 'Search-PiHoleListDomain', 'Add-PiHoleList', 'Remove-PiHoleList', `
#FTLInformation
'Get-PiHoleInfoMessage', 'Get-PiHoleInfoHost'
'Get-PiHoleInfoMessage', 'Get-PiHoleInfoHost', `
#History
'Get-PiHoleHistory', 'Get-PiHoleHistoryDatabase', 'Get-PiHoleHistoryClient', 'Get-PiHoleHistoryDatabaseClient'
)
50 changes: 38 additions & 12 deletions PiHoleShell/Public/GroupManagement/New-PiHoleGroup.ps1
Original file line number Diff line number Diff line change
@@ -1,8 +1,35 @@
function New-PiHoleGroup {
<#
.SYNOPSIS
Creates a new group in the groups object.
Creates a new group

.DESCRIPTION
Creates a new group in Pi-hole's groups object. Lists and clients can be assigned to groups
to apply blocking rules selectively rather than globally.

.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 GroupName
The name of the group to create

.PARAMETER Comment
An optional comment to store alongside the group

.PARAMETER Enabled
Whether the group is enabled immediately. Defaults to $true

.PARAMETER IgnoreSsl
Set to $true to skip SSL certificate validation

.PARAMETER RawOutput
This will dump the response instead of the formatted object

.EXAMPLE
New-PiHoleGroup -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" -GroupName "Kids"
#>
[CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#post-/groups')]
[Diagnostics.CodeAnalysis.SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "", Justification = "Ignoring for now")]
Expand Down Expand Up @@ -52,24 +79,23 @@ Creates a new group in the groups object.
}

else {
$ObjectFinal = @()
$Object = [PSCustomObject]@{
Name = $GroupName
Comment = $Comment
Enabled = $Enabled
$ObjectFinal = foreach ($Item in $Response.groups) {
[PSCustomObject]@{
Name = $Item.name
Comment = $Item.comment
Enabled = $Item.enabled
Id = $Item.id
DateAdded = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_added).LocalTime
DateModified = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_modified).LocalTime
}
}
Write-Verbose -Message "Name - $($Object.GroupName)"
Write-Verbose -Message "Comment - $($Object.Comment)"
Write-Verbose -Message "Enabled - $($Object.Enabled)"
$ObjectFinal = $Object
Write-Output $ObjectFinal
}
Write-Output $ObjectFinal
}
}

catch {
Write-Error -Message $_.Exception.Message
break
}

finally {
Expand Down
43 changes: 22 additions & 21 deletions PiHoleShell/Public/GroupManagement/Remove-PiHoleGroup.ps1
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
function Remove-PiHoleGroup {
<#
.SYNOPSIS
Delete group
Delete a group

.DESCRIPTION
Deletes a group from Pi-hole. Any lists or clients assigned to it are unassigned, not deleted.

.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 GroupName
The name of the group to delete

.PARAMETER IgnoreSsl
Set to $true to skip SSL certificate validation

.PARAMETER RawOutput
This will dump the response instead of the formatted object

.EXAMPLE
Remove-PiHoleGroup -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" -GroupName "Kids"
#>
#Work In Progress
[CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#delete-/groups/-name-')]
[Diagnostics.CodeAnalysis.SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "", Justification = "Ignoring for now")]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")]
Expand All @@ -34,8 +41,10 @@ This will dump the response instead of the formatted object
try {
$Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl

$Body = @{
name = $GroupName
$GetGroupName = Get-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl -GroupName $GroupName

if (-not $GetGroupName) {
throw "Cannot find $GroupName on $PiHoleServer! Please use Get-PiHoleGroup to list all groups"
}

$Params = @{
Expand All @@ -44,32 +53,24 @@ This will dump the response instead of the formatted object
Method = "Delete"
SkipCertificateCheck = $IgnoreSsl
ContentType = "application/json"
Body = $Body | ConvertTo-Json -Depth 10
}
$GetGroupName = Get-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl -GroupName $GroupName

if ($GetGroupName) {
$Response = Invoke-RestMethod @Params
$Response = Invoke-RestMethod @Params

if ($RawOutput) {
Write-Output $Response
}
else {
$ObjectFinal = @()
$Object = [PSCustomObject]@{
Name = $GroupName
Status = "Deleted"
}
$ObjectFinal = $Object
if ($RawOutput) {
Write-Output $Response
}
else {
$Object = [PSCustomObject]@{
Name = $GroupName
Status = "Deleted"
}
Write-Verbose -Message "Deleted $($Object.GroupName)"
Write-Output $ObjectFinal
Write-Output $Object
}
}

catch {
Write-Error -Message $_.Exception.Message
break
}

finally {
Expand Down
86 changes: 45 additions & 41 deletions PiHoleShell/Public/GroupManagement/Update-PiHoleGroup.ps1
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
function Update-PiHoleGroup {
<#
.SYNOPSIS
Items may be updated by replacing them.
Update a group

.DESCRIPTION
Updates a group's Comment and/or Enabled state. The underlying Pi-hole API replaces the
entire group on update, so any property you don't pass here is preserved by first reading
the group's current value and resending it - Comment and Enabled are never silently cleared
just because you only meant to change the other one.

.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 GroupName
The name of the group to update

.PARAMETER Comment
The new comment for the group. Leave unset to keep the group's current comment

.PARAMETER Enabled
Whether the group should be enabled. Leave unset to keep the group'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-PiHoleGroup -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" -GroupName "Kids" -Enabled $false
#>
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")]
[Diagnostics.CodeAnalysis.SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "", Justification = "Ignoring for now")]
Expand All @@ -26,41 +43,31 @@ This will dump the response instead of the formatted object
[string]$Password,
[Parameter(Mandatory = $true)]
[string]$GroupName,
[string]$Comment = $null,
[bool]$Enabled,
[string]$Comment,
[Nullable[bool]]$Enabled,
[bool]$IgnoreSsl = $false,
[bool]$RawOutput = $false

)
#Enabled is weird here.. look into it
try {
$Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl

$Body = @{
name = $GroupName
}

$GetGroupName = Get-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl -GroupName $GroupName

if ($Comment -eq $null -and $Enabled -eq $null) {
Write-Warning -Message "failed"
throw -Message "To update $GroupName, you must either use the Comment and/or Enabled parameter"
if (-not $GetGroupName) {
throw "Cannot find $GroupName on $PiHoleServer! Please use Get-PiHoleGroup to list all groups"
}

if ($Comment) {
$Body += @{
comment = $Comment
}
}
if ($Enabled -ne $null) {
$Body += @{
enabled = $Enabled
}
if (-not $PSBoundParameters.ContainsKey('Comment') -and -not $PSBoundParameters.ContainsKey('Enabled')) {
throw "To update $GroupName, you must specify the Comment and/or Enabled parameter"
}
else {
$Body += @{
enabled = $GetGroupName.Enabled
}

# The API replaces the whole group on update, so any property not explicitly passed
# here is resent using the group's current value to avoid silently clearing it.
$Body = @{
name = $GroupName
comment = if ($PSBoundParameters.ContainsKey('Comment')) { $Comment } else { $GetGroupName.Comment }
enabled = if ($PSBoundParameters.ContainsKey('Enabled')) { $Enabled } else { $GetGroupName.Enabled }
}

$Params = @{
Expand All @@ -72,31 +79,28 @@ This will dump the response instead of the formatted object
Body = $Body | ConvertTo-Json -Depth 10
}

if ($GetGroupName) {
$Response = Invoke-RestMethod @Params
if ($RawOutput) {
Write-Output $Response
}
else {
$ObjectFinal = @()
$Object = [PSCustomObject]@{
Name = $GroupName
Comment = $Comment
Enabled = $Enabled
$Response = Invoke-RestMethod @Params

if ($RawOutput) {
Write-Output $Response
}
else {
$ObjectFinal = foreach ($Item in $Response.groups) {
[PSCustomObject]@{
Name = $Item.name
Comment = $Item.comment
Enabled = $Item.enabled
Id = $Item.id
DateAdded = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_added).LocalTime
DateModified = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.date_modified).LocalTime
}
Write-Verbose -Message "Name - $($Object.GroupName)"
Write-Verbose -Message "Comment - $($Object.Comment)"
Write-Verbose -Message "Enabled - $($Object.Enabled)"
$ObjectFinal = $Object
}
Write-Output $ObjectFinal

}
}

catch {
Write-Error -Message $_.Exception.Message
break
}

finally {
Expand Down
77 changes: 77 additions & 0 deletions PiHoleShell/Public/History/Get-PiHoleHistory.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
function Get-PiHoleHistory {
<#
.SYNOPSIS
Get activity graph data

.DESCRIPTION
Request the data needed to generate the "total queries over time" graph, covering roughly
the last 24 hours. The sum of Cached/Blocked/Forwarded for a given entry may be smaller than
Total - the remainder are queries that don't fit into any of those categories (e.g. a busy
database, or an unknown query status).

.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 IgnoreSsl
Set to $true to skip SSL certificate validation

.PARAMETER RawOutput
This will dump the response instead of the formatted object

.EXAMPLE
Get-PiHoleHistory -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password"
#>
[CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#get-/history')]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")]
param (
[Parameter(Mandatory = $true)]
[System.URI]$PiHoleServer,
[Parameter(Mandatory = $true)]
[string]$Password,
[bool]$IgnoreSsl = $false,
[bool]$RawOutput = $false
)

try {
$Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl

$Params = @{
Headers = @{sid = $($Sid) }
Uri = "$($PiHoleServer.OriginalString)/api/history"
Method = "Get"
SkipCertificateCheck = $IgnoreSsl
ContentType = "application/json"
}

$Response = Invoke-RestMethod @Params

if ($RawOutput) {
Write-Output $Response
}
else {
$ObjectFinal = foreach ($Item in $Response.history) {
[PSCustomObject]@{
Timestamp = (Convert-PiHoleUnixTimeToLocalTime -UnixTime $Item.timestamp).LocalTime
Total = $Item.total
Cached = $Item.cached
Blocked = $Item.blocked
Forwarded = $Item.forwarded
}
}
Write-Output $ObjectFinal
}
}

catch {
Write-Error -Message $_.Exception.Message
}

finally {
if ($Sid) {
Remove-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Sid $Sid -IgnoreSsl $IgnoreSsl
}
}
}
Loading
Loading