Public/Get-PiHoleDbHistoryClients.ps1
function Get-PiHoleDbHistoryClients { <# .SYNOPSIS Retrieves per-client activity graph data (long-term data) from the Pi-hole API. .DESCRIPTION This function authenticates to the Pi-hole API using Connect-PiHole, retrieves long-term per-client data needed to generate the client activity graph, and then disconnects the session using Disconnect-PiHole. .PARAMETER BaseUrl The base URL of the Pi-hole instance (e.g., http://pi.hole). .PARAMETER Credential A PSCredential object containing the Pi-hole password. .PARAMETER From DateTime from when the data should be requested. Accepts DateTime objects or date strings like '5-7-2025 3:34PM'. .PARAMETER Until DateTime until when the data should be requested. Accepts DateTime objects or date strings like '5-7-2025 3:34PM'. .OUTPUTS A PSCustomObject containing the client history data, clients information, and processing time. .EXAMPLE $cred = Get-Credential $from = Get-Date "2023-01-01 12:00:00" $until = Get-Date "2023-01-02 12:00:00" Get-PiHoleDbHistoryClients -BaseUrl 'http://pi.hole' -Credential $cred -From $from -Until $until .EXAMPLE # Using string dates directly $cred = Get-Credential Get-PiHoleDbHistoryClients -BaseUrl 'http://pi.hole' -Credential $cred -From '5-7-2025 3:34PM' -Until '5-7-2025 11:59PM' .EXAMPLE # Get client data for the last 24 hours $cred = Get-Credential $until = Get-Date $from = $until.AddDays(-1) Get-PiHoleDbHistoryClients -BaseUrl 'http://pi.hole' -Credential $cred -From $from -Until $until #> param ( [Parameter(Mandatory = $true)] [string]$BaseUrl, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential]$Credential, [Parameter(Mandatory = $true)] [DateTime]$From, [Parameter(Mandatory = $true)] [DateTime]$Until ) begin { # Validate BaseUrl uses http if (-not $BaseUrl.StartsWith('http://')) { throw "Error: BaseUrl must use the 'http' scheme." } # Validate DateTime parameters if ($From -gt $Until) { throw "Error: From DateTime cannot be greater than Until DateTime." } } process { $sessionData = $null try { Write-Verbose "Starting authentication to Pi-hole at $BaseUrl" # Authenticate and get session data $sessionData = Connect-PiHole -BaseUrl $BaseUrl -Credential $Credential Write-Verbose "Authentication successful. Session ID: $($sessionData.ID), SID: $($sessionData.SID)" # Convert DateTime to Unix timestamps for API call $fromUnix = [DateTimeOffset]::new($From).ToUnixTimeSeconds() $untilUnix = [DateTimeOffset]::new($Until).ToUnixTimeSeconds() Write-Verbose "Converted dates - From: $From ($fromUnix), Until: $Until ($untilUnix)" # Prepare API request to get client history data $url = "$BaseUrl/api/history/database/clients?from=$fromUnix&until=$untilUnix" Write-Verbose "Making API request to: $url" $headers = @{ 'X-FTL-SID' = $sessionData.SID } $response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers -ErrorAction Stop Write-Verbose "API request successful. Response contains $($response.history.Count) history entries and $($response.clients.PSObject.Properties.Count) clients" # Return the response as-is Write-Verbose "Successfully retrieved client history data" return $response } catch { Write-Error "Error occurred: $($_.Exception.Message)" Write-Verbose "Full error details: $($_ | Out-String)" # Try to disconnect if we have session data if ($sessionData -and $sessionData.ID -and $sessionData.SID) { Write-Verbose "Attempting to disconnect session due to error..." try { Disconnect-PiHole -BaseUrl $BaseUrl -Id $sessionData.ID -SID $sessionData.SID Write-Verbose "Session disconnected successfully" } catch { Write-Warning "Failed to disconnect session: $($_.Exception.Message)" } } throw } finally { # Clean disconnect in finally block if ($sessionData -and $sessionData.ID -and $sessionData.SID) { Write-Verbose "Attempting final session cleanup..." try { Disconnect-PiHole -BaseUrl $BaseUrl -Id $sessionData.ID -SID $sessionData.SID Write-Verbose "Final session cleanup completed successfully" } catch { Write-Warning "Failed to clean up session in finally block: $($_.Exception.Message)" } } } } end { # Nothing to clean up in the end block } } |