diff --git a/PiHoleShell/PiHoleShell.psm1 b/PiHoleShell/PiHoleShell.psm1 index a9c4685..3be29b1 100644 --- a/PiHoleShell/PiHoleShell.psm1 +++ b/PiHoleShell/PiHoleShell.psm1 @@ -18,7 +18,7 @@ Export-ModuleMember -Function @( #Actions 'Update-PiHoleActionsGravity', 'Invoke-PiHoleFlushNetwork', 'Invoke-PiHoleFlushLogs', 'Restart-PiHoleDnsService' ` #Authentication - 'Remove-PiHoleCurrentAuthSession' , 'Get-PiHoleCurrentAuthSession', 'Remove-PiHoleAuthSession', ` + 'Remove-PiHoleCurrentAuthSession' , 'Get-PiHoleCurrentAuthSession', 'Remove-PiHoleAuthSession', 'Get-PiHoleAuthStatus', 'Get-PiHoleAuthTotp', ` #GroupManagement 'Get-PiHoleGroup', 'New-PiHoleGroup', 'Update-PiHoleGroup', 'Remove-PiHoleGroup', ` #DnsControl diff --git a/PiHoleShell/Public/Authentication/Get-PiHoleAuthStatus.ps1 b/PiHoleShell/Public/Authentication/Get-PiHoleAuthStatus.ps1 new file mode 100644 index 0000000..3666bb7 --- /dev/null +++ b/PiHoleShell/Public/Authentication/Get-PiHoleAuthStatus.ps1 @@ -0,0 +1,82 @@ +function Get-PiHoleAuthStatus { + <# +.SYNOPSIS +Check if authentication is required + +.DESCRIPTION +Checks whether your Pi-hole requires a login for the calling client. Some Pi-hole +configurations skip authentication entirely for trusted local clients, in which case this +reports a valid session without needing a password at all. Pass -Password to instead check +the status of a real login with that password. + +.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. Optional - omit it to check whether +your Pi-hole requires a login at all for this client, without authenticating. + +.PARAMETER IgnoreSsl +Set to $true to skip SSL certificate validation + +.PARAMETER RawOutput +This will dump the response instead of the formatted object + +.EXAMPLE +Get-PiHoleAuthStatus -PiHoleServer "http://pihole.domain.com:8080" + +.EXAMPLE +Get-PiHoleAuthStatus -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" + #> + [CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#get-/auth')] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] + param ( + [Parameter(Mandatory = $true)] + [System.URI]$PiHoleServer, + [string]$Password, + [bool]$IgnoreSsl = $false, + [bool]$RawOutput = $false + ) + try { + if ($PSBoundParameters.ContainsKey('Password')) { + $Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl + } + + $Params = @{ + Uri = "$($PiHoleServer.OriginalString)/api/auth" + Method = "Get" + SkipCertificateCheck = $IgnoreSsl + ContentType = "application/json" + } + if ($Sid) { + $Params.Headers = @{sid = $($Sid) } + } + + $Response = Invoke-RestMethod @Params + + if ($RawOutput) { + Write-Output $Response + } + else { + $Object = [PSCustomObject]@{ + Valid = $Response.session.valid + Totp = $Response.session.totp + Sid = $Response.session.sid + Csrf = $Response.session.csrf + Validity = $Response.session.validity + Message = $Response.session.message + } + Write-Output $Object + } + } + + catch { + Write-Error -Message $_.Exception.Message + } + + finally { + if ($Sid) { + Remove-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Sid $Sid -IgnoreSsl $IgnoreSsl + } + } +} diff --git a/PiHoleShell/Public/Authentication/Get-PiHoleAuthTotp.ps1 b/PiHoleShell/Public/Authentication/Get-PiHoleAuthTotp.ps1 new file mode 100644 index 0000000..427248c --- /dev/null +++ b/PiHoleShell/Public/Authentication/Get-PiHoleAuthTotp.ps1 @@ -0,0 +1,76 @@ +function Get-PiHoleAuthTotp { + <# +.SYNOPSIS +Suggest new TOTP credentials + +.DESCRIPTION +Suggests new TOTP credentials for setting up two-factor authentication (2FA) on your Pi-hole. +This only suggests a secret; it does not enable 2FA by itself. + +.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-PiHoleAuthTotp -PiHoleServer "http://pihole.domain.com:8080" -Password "your-app-password" + #> + [CmdletBinding(HelpUri = 'https://ftl.pi-hole.net/master/docs/#get-/auth/totp')] + [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/auth/totp" + Method = "Get" + SkipCertificateCheck = $IgnoreSsl + ContentType = "application/json" + } + + $Response = Invoke-RestMethod @Params + + if ($RawOutput) { + Write-Output $Response + } + else { + $Object = [PSCustomObject]@{ + Type = $Response.totp.type + Account = $Response.totp.account + Issuer = $Response.totp.issuer + Algorithm = $Response.totp.algorithm + Digits = $Response.totp.digits + Period = $Response.totp.period + Offset = $Response.totp.offset + Secret = $Response.totp.secret + Codes = $Response.totp.codes + } + Write-Output $Object + } + } + + catch { + Write-Error -Message $_.Exception.Message + } + + finally { + if ($Sid) { + Remove-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Sid $Sid -IgnoreSsl $IgnoreSsl + } + } +} diff --git a/README.md b/README.md index 14a562d..ac3af28 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,8 @@ Session handling is automatic for every command above, but these are available f | Function | Description | |---|---| +| `Get-PiHoleAuthStatus` | Check if authentication is required | +| `Get-PiHoleAuthTotp` | Suggest new TOTP credentials | | `Get-PiHoleCurrentAuthSession` | List of all current sessions including their validity and further information about the client such as the IP address and user agent. | | `Remove-PiHoleAuthSession` | Using this endpoint, a session can be deleted by its ID. | diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 3d35681..a701363 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -99,9 +99,9 @@ New-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -GroupName "PiHo Name : PiHoleShellDocsExampleGroup Comment : Example group Enabled : True -Id : 60 -DateAdded : 9/30/2026 4:22:23 PM -DateModified : 9/30/2026 4:22:23 PM +Id : 57 +DateAdded : 10/1/2026 3:13:46 PM +DateModified : 10/1/2026 3:13:46 PM ``` ### Get-PiHoleGroup @@ -143,9 +143,9 @@ DateModified : 9/30/2026 8:48:26 AM Name : PiHoleShellDocsExampleGroup Comment : Example group Enabled : True -Id : 60 -DateAdded : 9/30/2026 4:22:23 PM -DateModified : 9/30/2026 4:22:23 PM +Id : 57 +DateAdded : 10/1/2026 3:13:46 PM +DateModified : 10/1/2026 3:13:46 PM ``` ### Update-PiHoleGroup @@ -159,9 +159,9 @@ Update-PiHoleGroup -PiHoleServer $PiHoleServer -Password $Password -GroupName "P Name : PiHoleShellDocsExampleGroup Comment : Example group Enabled : False -Id : 60 -DateAdded : 9/30/2026 4:22:23 PM -DateModified : 9/30/2026 4:22:41 PM +Id : 57 +DateAdded : 10/1/2026 3:13:46 PM +DateModified : 10/1/2026 3:14:04 PM ``` ### Remove-PiHoleGroup @@ -191,8 +191,8 @@ Comment : Example list Groups : {Default} Enabled : True Id : 71 -DateAdded : 9/30/2026 4:23:18 PM -DateModified : 9/30/2026 4:23:18 PM +DateAdded : 10/1/2026 3:14:41 PM +DateModified : 10/1/2026 3:14:41 PM Type : Block DateUpdated : Number : 0 @@ -295,8 +295,8 @@ Comment : Example list Groups : {Default} Enabled : False Id : 71 -DateAdded : 9/30/2026 4:23:18 PM -DateModified : 9/30/2026 4:23:51 PM +DateAdded : 10/1/2026 3:14:41 PM +DateModified : 10/1/2026 3:15:14 PM Type : Block DateUpdated : Number : 0 @@ -422,8 +422,8 @@ Comment : Example domain Groups : {Default} Enabled : True Id : 22 -DateAdded : 9/30/2026 4:24:29 PM -DateModified : 9/30/2026 4:24:29 PM +DateAdded : 10/1/2026 3:15:52 PM +DateModified : 10/1/2026 3:15:52 PM ``` ### Get-PiHoleDomain @@ -442,8 +442,8 @@ Comment : Example domain Groups : {Default} Enabled : True Id : 22 -DateAdded : 9/30/2026 4:24:29 PM -DateModified : 9/30/2026 4:24:29 PM +DateAdded : 10/1/2026 3:15:52 PM +DateModified : 10/1/2026 3:15:52 PM ``` ### Update-PiHoleDomain @@ -462,8 +462,8 @@ Comment : Example domain Groups : {Default} Enabled : False Id : 22 -DateAdded : 9/30/2026 4:24:29 PM -DateModified : 9/30/2026 4:25:02 PM +DateAdded : 10/1/2026 3:15:52 PM +DateModified : 10/1/2026 3:16:25 PM ``` ### Remove-PiHoleDomain @@ -494,9 +494,9 @@ Client : 192.168.99.99 Name : Comment : Example client Groups : {Default} -Id : 23 -DateAdded : 9/30/2026 4:25:33 PM -DateModified : 9/30/2026 4:25:33 PM +Id : 22 +DateAdded : 10/1/2026 3:16:56 PM +DateModified : 10/1/2026 3:16:56 PM ``` ### Get-PiHoleClient @@ -511,9 +511,9 @@ Client : 192.168.99.99 Name : Comment : Example client Groups : {Default} -Id : 23 -DateAdded : 9/30/2026 4:25:33 PM -DateModified : 9/30/2026 4:25:33 PM +Id : 22 +DateAdded : 10/1/2026 3:16:56 PM +DateModified : 10/1/2026 3:16:56 PM ``` ### Get-PiHoleClientSuggestion @@ -526,13 +526,13 @@ Get-PiHoleClientSuggestion -PiHoleServer $PiHoleServer -Password $Password HwAddr : ip-127.0.0.1 MacVendor : -LastQuery : 9/30/2026 4:19:28 PM +LastQuery : 10/1/2026 3:00:00 PM Addresses : 127.0.0.1 Names : localhost HwAddr : 74:56:3c:bb:f4:0b MacVendor : Giga-Byte Technology Co.,Ltd. -LastQuery : 9/30/2026 4:19:27 PM +LastQuery : 10/1/2026 9:03:33 AM Addresses : 192.168.1.162 Names : ``` @@ -549,9 +549,9 @@ Client : 192.168.99.99 Name : Comment : Updated comment Groups : {Default} -Id : 23 -DateAdded : 9/30/2026 4:25:33 PM -DateModified : 9/30/2026 4:26:12 PM +Id : 22 +DateAdded : 10/1/2026 3:16:56 PM +DateModified : 10/1/2026 3:17:35 PM ``` ### Remove-PiHoleClient @@ -576,18 +576,18 @@ Get-PiHoleStatsSummary -PiHoleServer $PiHoleServer -Password $Password ``` -Total : 42 -Blocked : 8 -PercentBlocked : 19.0476188659668 +Total : 52 +Blocked : 10 +PercentBlocked : 19.230770111084 UniqueDomains : 15 Forwarded : 27 -Cached : 7 +Cached : 15 Frequency : 0 -Types : @{A=19; AAAA=20; ANY=0; SRV=0; SOA=0; PTR=3; TXT=0; NAPTR=0; MX=0; DS=0; RRSIG=0; DNSKEY=0; NS=0; SVCB=0; HTTPS=0; OTHER=0} -Status : @{Unknown=0; Gravity=8; Forwarded=27; Cache=7; Regex=0; DenyList=0; ExternalBlockedIp=0; ExternalBlockedNull=0; ExternalBlockedNxra=0; GravityCname=0; RegexCname=0; DenyListCname=0; Retired=0; RetiredDnssec=0; InProgress=0; Dbbusy=0; SpecialDomain=0; CacheStale=0; ExternalBlockedEde15=0} -Replies : @{Unknown=10; Nodata=2; Nxdomain=1; Cname=0; Ip=27; Domain=2; Rrname=0; ServFail=0; Refused=0; Notimp=0; Other=0; Dnssec=0; None=0; Blob=0} +Types : @{A=20; AAAA=19; ANY=0; SRV=0; SOA=0; PTR=13; TXT=0; NAPTR=0; MX=0; DS=0; RRSIG=0; DNSKEY=0; NS=0; SVCB=0; HTTPS=0; OTHER=0} +Status : @{Unknown=0; Gravity=10; Forwarded=27; Cache=15; Regex=0; DenyList=0; ExternalBlockedIp=0; ExternalBlockedNull=0; ExternalBlockedNxra=0; GravityCname=0; RegexCname=0; DenyListCname=0; Retired=0; RetiredDnssec=0; InProgress=0; Dbbusy=0; SpecialDomain=0; CacheStale=0; ExternalBlockedEde15=0} +Replies : @{Unknown=10; Nodata=3; Nxdomain=3; Cname=0; Ip=26; Domain=10; Rrname=0; ServFail=0; Refused=0; Notimp=0; Other=0; Dnssec=0; None=0; Blob=0} Clients : @{Active=2; Total=2} -Gravity : @{DomainsBeingBlocked=494952; LastUpdate=1790799702} +Gravity : @{DomainsBeingBlocked=495564; LastUpdate=1790861541} ``` ### Get-PiHoleStatsRecentBlocked @@ -598,7 +598,7 @@ Get-PiHoleStatsRecentBlocked -PiHoleServer $PiHoleServer -Password $Password ``` -Blocked : adservice.google.com +Blocked : googleadservices.com ``` ### Get-PiHoleStatsQueryType @@ -610,10 +610,10 @@ Get-PiHoleStatsQueryType -PiHoleServer $PiHoleServer -Password $Password ``` Type : A -Count : 19 +Count : 20 Type : AAAA -Count : 20 +Count : 19 Type : ANY Count : 0 @@ -635,13 +635,10 @@ Get-PiHoleStatsTopDomain -PiHoleServer $PiHoleServer -Password $Password ``` -Domain : mozilla.org -Count : 4 - -Domain : bbc.com -Count : 4 +Domain : 1.0.0.127.in-addr.arpa +Count : 7 -Domain : stackoverflow.com +Domain : example.com Count : 4 Domain : cloudflare.com @@ -650,6 +647,9 @@ Count : 4 Domain : reddit.com Count : 4 +Domain : bbc.com +Count : 4 + _(showing 5 of 10 results)_ ``` @@ -667,7 +667,7 @@ Count : 39 IP : 127.0.0.1 Name : localhost -Count : 3 +Count : 13 ``` ### Get-PiHoleStatsUpstream @@ -678,9 +678,9 @@ Get-PiHoleStatsUpstream -PiHoleServer $PiHoleServer -Password $Password ``` -TotalQueries : 42 +TotalQueries : 52 ForwardedQueries : 27 -Upstreams : {@{Ip=blocklist; Name=blocklist; Port=-1; Count=8; ResponseTime=0; Variance=0}, @{Ip=cache; Name=cache; Port=-1; Count=7; ResponseTime=0; Variance=0}, @{Ip=8.8.8.8; Name=dns.google; Port=53; Count=27; ResponseTime=0.0287302732467651; Variance=0.00306724246755919}} +Upstreams : {@{Ip=blocklist; Name=blocklist; Port=-1; Count=10; ResponseTime=0; Variance=0}, @{Ip=cache; Name=cache; Port=-1; Count=15; ResponseTime=0; Variance=0}, @{Ip=8.8.8.8; Name=dns.google; Port=53; Count=27; ResponseTime=0.0202921777963638; Variance=0.00264818341859654}} ``` ### Get-PiHoleStatsQuerySuggestions @@ -691,7 +691,7 @@ Get-PiHoleStatsQuerySuggestions -PiHoleServer $PiHoleServer -Password $Password ``` -Domain : {mozilla.org, bbc.com, stackoverflow.com, cloudflare.com…} +Domain : {1.0.0.127.in-addr.arpa, example.com, cloudflare.com, reddit.com…} ClientIp : {192.168.1.162, 127.0.0.1} ClientName : {localhost} Upstream : {blocklist, cache, 8.8.8.8#53 (dns.google), permitted} @@ -711,9 +711,9 @@ Get-PiHoleStatsDatabaseSummary -PiHoleServer $PiHoleServer -Password $Password ``` -SumQueries : 42 -SumBlocked : 8 -PercentBlocked : 19.0476188659668 +SumQueries : 52 +SumBlocked : 10 +PercentBlocked : 19.230770111084 TotalClients : 3 ``` @@ -728,7 +728,7 @@ Get-PiHoleStatsDatabaseQueryType -PiHoleServer $PiHoleServer -Password $Password ``` Type : A -Count : 20 +Count : 19 Type : AAAA Count : 0 @@ -740,7 +740,7 @@ Type : SRV Count : 0 Type : SOA -Count : 3 +Count : 13 _(showing 5 of 16 results)_ ``` @@ -755,13 +755,13 @@ Get-PiHoleStatsDatabaseTopDomain -PiHoleServer $PiHoleServer -Password $Password ``` -Domain : nytimes.com -Count : 4 +Domain : 1.0.0.127.in-addr.arpa +Count : 7 Domain : bbc.com Count : 4 -Domain : mozilla.org +Domain : wikipedia.org Count : 4 Domain : example.com @@ -785,15 +785,15 @@ Get-PiHoleStatsDatabaseTopClient -PiHoleServer $PiHoleServer -Password $Password IP : 192.168.1.162 Name : -Count : 31 +Count : 29 IP : 127.0.0.1 -Name : -Count : 2 +Name : localhost +Count : 11 IP : 127.0.0.1 -Name : localhost -Count : 1 +Name : +Count : 2 ``` ### Get-PiHoleStatsDatabaseUpstream @@ -806,9 +806,9 @@ Get-PiHoleStatsDatabaseUpstream -PiHoleServer $PiHoleServer -Password $Password ``` -TotalQueries : 42 +TotalQueries : 52 ForwardedQueries : 27 -Upstreams : {@{Ip=2; Name=; Port=4294967295; Count=27; ResponseTime=0; Variance=0}, @{Ip=cache; Name=cache; Port=-1; Count=7; ResponseTime=0; Variance=0}, @{Ip=blocklist; Name=blocklist; Port=-1; Count=8; ResponseTime=0; Variance=0}} +Upstreams : {@{Ip=2; Name=; Port=4294967295; Count=27; ResponseTime=0; Variance=0}, @{Ip=cache; Name=cache; Port=-1; Count=15; ResponseTime=0; Variance=0}, @{Ip=blocklist; Name=blocklist; Port=-1; Count=10; ResponseTime=0; Variance=0}} ``` ### Get-PiHoleQuery @@ -821,69 +821,69 @@ Get-PiHoleQuery -PiHoleServer $PiHoleServer -Password $Password -Length 5 ``` -Id : 41 -Time : 9/30/2026 4:19:28 PM +Id : 51 +Time : 10/1/2026 3:00:00 PM Type : PTR Domain : 1.0.0.127.in-addr.arpa Cname : Status : CACHE Client : @{Ip=127.0.0.1; Name=localhost} Dnssec : UNKNOWN -Reply : @{Type=DOMAIN; Time=0.0016322135925293} +Reply : @{Type=DOMAIN; Time=0.000154972076416016} ListId : Upstream : Ede : @{Code=-1; Text=} -Id : 40 -Time : 9/30/2026 4:19:28 PM -Type : AAAA -Domain : adservice.google.com +Id : 50 +Time : 10/1/2026 2:00:01 PM +Type : PTR +Domain : 1.0.0.127.in-addr.arpa Cname : -Status : GRAVITY -Client : @{Ip=192.168.1.162; Name=} +Status : CACHE +Client : @{Ip=127.0.0.1; Name=localhost} Dnssec : UNKNOWN -Reply : @{Type=IP; Time=0.00115633010864258} -ListId : -53 +Reply : @{Type=DOMAIN; Time=0.000155925750732422} +ListId : Upstream : Ede : @{Code=-1; Text=} -Id : 39 -Time : 9/30/2026 4:19:28 PM -Type : A -Domain : adservice.google.com +Id : 49 +Time : 10/1/2026 1:00:00 PM +Type : PTR +Domain : 1.0.0.127.in-addr.arpa Cname : -Status : GRAVITY -Client : @{Ip=192.168.1.162; Name=} +Status : CACHE +Client : @{Ip=127.0.0.1; Name=localhost} Dnssec : UNKNOWN -Reply : @{Type=IP; Time=0.00106549263000488} -ListId : -53 +Reply : @{Type=DOMAIN; Time=0.000154018402099609} +ListId : Upstream : Ede : @{Code=-1; Text=} -Id : 38 -Time : 9/30/2026 4:19:28 PM -Type : AAAA -Domain : microsoft.com +Id : 48 +Time : 10/1/2026 12:00:00 PM +Type : PTR +Domain : 1.0.0.127.in-addr.arpa Cname : Status : CACHE -Client : @{Ip=192.168.1.162; Name=} +Client : @{Ip=127.0.0.1; Name=localhost} Dnssec : UNKNOWN -Reply : @{Type=IP; Time=0.000108957290649414} +Reply : @{Type=DOMAIN; Time=0.000212192535400391} ListId : Upstream : Ede : @{Code=-1; Text=} -Id : 37 -Time : 9/30/2026 4:19:28 PM -Type : AAAA -Domain : microsoft.com +Id : 47 +Time : 10/1/2026 11:00:01 AM +Type : PTR +Domain : 8.8.8.8.in-addr.arpa Cname : -Status : FORWARDED -Client : @{Ip=192.168.1.162; Name=} +Status : CACHE +Client : @{Ip=127.0.0.1; Name=localhost} Dnssec : UNKNOWN -Reply : @{Type=IP; Time=0.0397381782531738} +Reply : @{Type=DOMAIN; Time=0.00014805793762207} ListId : -Upstream : 8.8.8.8#53 +Upstream : Ede : @{Code=-1; Text=} ``` @@ -978,20 +978,20 @@ CpuPercent : 0 MemoryPercent : 0 ActiveClients : 2 Blocking : enabled -Cache : @{Size=10000; Inserted=38; Evicted=0} +Cache : @{Size=10000; Inserted=35; Evicted=0} Config : @{DhcpActive=False; DhcpStart=; DhcpEnd=; DhcpIpv6=False; DnsDnssec=False; DnsDomain=lan; DnsNumUpstreams=2; DnsPort=53; DnsrevServerAactive=False; PrivacyLevel=0} -GravitySize : 494952 +GravitySize : 495564 HostModel : Raspberry Pi Zero W Rev 1.1 IFace : @{v4=; v6=} NodeName : dns3.localdomain Pid : 388 -Queries : @{Total=42; Blocked=8; PercentBlocked=19.0476188659668; QueryFrequency=0} -RecentBlocked : adservice.google.com -Sensors : @{CpuTemp=41.698; HotLimit=60; Unit=C} -System : @{Uptime=153598; Memory=; Procs=73; Cpu=; Ftl=} +Queries : @{Total=52; Blocked=10; PercentBlocked=19.230770111084; QueryFrequency=0} +RecentBlocked : googleadservices.com +Sensors : @{CpuTemp=39.546; HotLimit=60; Unit=C} +System : @{Uptime=235882; Memory=; Procs=72; Cpu=; Ftl=} TopBlocked : googleadservices.com TopClient : 192.168.1.162 -TopDomain : nytimes.com +TopDomain : 1.0.0.127.in-addr.arpa Version : @{Core=; Web=; Ftl=; Docker=} ``` @@ -1028,11 +1028,11 @@ Get-PiHoleInfoSystem -PiHoleServer $PiHoleServer -Password $Password ``` -Uptime : 153609 +Uptime : 235892 Memory : @{Ram=; Swap=} -Procs : 73 -Cpu : @{NumProcessors=1; PercentCpu=96.5; Load=} -Ftl : @{PercentMemory=3.01092410087585; PercentCpu=96} +Procs : 74 +Cpu : @{NumProcessors=1; PercentCpu=97.1999969482422; Load=} +Ftl : @{PercentMemory=2.52266621589661; PercentCpu=96.4000015258789} ``` ### Get-PiHoleInfoFtl @@ -1043,16 +1043,16 @@ Get-PiHoleInfoFtl -PiHoleServer $PiHoleServer -Password $Password ``` -Database : @{Gravity=494952; Antigravity=0; Groups=4; Lists=14; Clients=0; Domains=; Regex=} +Database : @{Gravity=495564; Antigravity=0; Groups=4; Lists=14; Clients=0; Domains=; Regex=} PrivacyLevel : 0 QueryFrequency : 0 Clients : @{Total=2; Active=2} Pid : 388 -Uptime : 3776419.413644 -PercentMemory : 3.01092410087585 +Uptime : 24254906.207769 +PercentMemory : 2.52266621589661 PercentCpu : 96.4000015258789 AllowDestructive : True -Dnsmasq : @{DnsCacheInserted=38; DnsCacheLiveFreed=0; DnsQueriesForwarded=27; DnsAuthAnswered=0; DnsLocalAnswered=15; DnsStaleAnswered=0; DnsUnanswered=0; DnssecMaxCryptoUse=0; DnssecMaxSigFail=0; DnssecMaxWork=0; Bootp=0; Pxe=0; DhcpAck=0; DhcpDecline=0; DhcpDiscover=0; DhcpInform=0; DhcpNak=0; DhcpOffer=0; DhcpRelease=0; DhcpRequest=0; Noanswer=0; LeasesAllocated4=0; LeasesPruned4=0; LeasesAllocated6=0; LeasesPruned6=0; TcpConnections=0; DhcpLeasequery=0; DhcpLeaseUnassigned=0; DhcpLeaseActve=0; DhcpLeaseUnknown=0} +Dnsmasq : @{DnsCacheInserted=35; DnsCacheLiveFreed=0; DnsQueriesForwarded=27; DnsAuthAnswered=0; DnsLocalAnswered=25; DnsStaleAnswered=0; DnsUnanswered=0; DnssecMaxCryptoUse=0; DnssecMaxSigFail=0; DnssecMaxWork=0; Bootp=0; Pxe=0; DhcpAck=0; DhcpDecline=0; DhcpDiscover=0; DhcpInform=0; DhcpNak=0; DhcpOffer=0; DhcpRelease=0; DhcpRequest=0; Noanswer=0; LeasesAllocated4=0; LeasesPruned4=0; LeasesAllocated6=0; LeasesPruned6=0; TcpConnections=0; DhcpLeasequery=0; DhcpLeaseUnassigned=0; DhcpLeaseActve=0; DhcpLeaseUnknown=0} ``` ### Get-PiHoleInfoSensors @@ -1064,7 +1064,7 @@ Get-PiHoleInfoSensors -PiHoleServer $PiHoleServer -Password $Password ``` List : {@{Name=cpu_thermal; Path=hwmon0; Source=devices/virtual/thermal/thermal_zone0; Temps=}, @{Name=rpi_volt; Path=hwmon1; Source=devices/platform/soc/soc:firmware/raspberrypi-hwmon; Temps=}} -CpuTemp : 41.16 +CpuTemp : 40.084 HotLimit : 60 Unit : C ``` @@ -1081,12 +1081,12 @@ Size : 13983744 Type : Regular file Mode : rw-r----- AccessTime : 6/25/2025 12:32:44 AM -ModifiedTime : 9/30/2026 3:18:14 PM -ChangeTime : 9/30/2026 3:18:15 PM +ModifiedTime : 10/1/2026 2:06:00 PM +ChangeTime : 10/1/2026 2:06:00 PM Owner : @{User=; Group=} -Queries : 42 -EarliestTimestamp : 9/29/2026 4:20:00 PM -QueriesDisk : 42 +Queries : 52 +EarliestTimestamp : 9/30/2026 3:10:00 PM +QueriesDisk : 52 EarliestTimestampDisk : SqliteVersion : 3.53.1 ``` @@ -1155,17 +1155,17 @@ Get-PiHoleInfoMessage -PiHoleServer $PiHoleServer -Password $Password ``` -Id : 22 -Timestamp : 9/30/2026 4:16:55 PM +Id : 1 +Timestamp : 10/1/2026 8:28:21 AM Type : LIST Plain : List with ID 63 (https://codeberg.org/hagezi/mirror2/raw/branch/main/dns-blocklists/domains/light.txt) was inaccessible during last gravity run Html : List with ID 63 (https://codeberg.org/hagezi/mirror2/raw/branch/main/dns-blocklists/domains/light.txt) was inaccessible during last gravity run -Id : 23 -Timestamp : 9/30/2026 4:18:16 PM +Id : 2 +Timestamp : 10/1/2026 9:38:21 AM Type : LOAD -Plain : Long-term load (15min avg) larger than number of processors: 1.9 > 1 -Html : Long-term load (15min avg) larger than number of processors: 1.9 > 1
This may slow down DNS resolution and can cause bottlenecks. +Plain : Long-term load (15min avg) larger than number of processors: 1.0 > 1 +Html : Long-term load (15min avg) larger than number of processors: 1.0 > 1
This may slow down DNS resolution and can cause bottlenecks. ``` ### Get-PiHoleInfoMessageCount @@ -1200,8 +1200,8 @@ Get-PiHoleLogWebserver -PiHoleServer $PiHoleServer -Password $Password ``` -Log : {@{Timestamp=9/30/2026 3:18:16 PM; Message=Initializing HTTP server on ports "8089,8489s"; Priority=}, @{Timestamp=9/30/2026 3:29:52 PM; Message=ACCESS: 192.168.1.162 - - [30/Sep/2026:20:29:51 +0000] "PATCH /api/config?restart=false HTTP/1.1" 200 4588 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}, @{Timestamp=9/30/2026 3:29:53 PM; Message=ACCESS: 192.168.1.162 - - [30/Sep/2026:20:29:52 +0000] "DELETE /api/auth HTTP/1.1" 204 558 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}, @{Timestamp=9/30/2026 3:29:54 PM; Message=ACCESS: 192.168.1.162 - - [30/Sep/2026:20:29:45 +0000] "POST /api/auth HTTP/1.1" 200 806 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}…} -NextID : 33 +Log : {@{Timestamp=10/1/2026 8:28:22 AM; Message=Initializing HTTP server on ports "8089,8489s"; Priority=}, @{Timestamp=10/1/2026 8:31:16 AM; Message=ACCESS: 192.168.1.162 - - [01/Oct/2026:13:31:15 +0000] "PATCH /api/config?restart=false HTTP/1.1" 200 4588 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}, @{Timestamp=10/1/2026 8:31:17 AM; Message=ACCESS: 192.168.1.162 - - [01/Oct/2026:13:31:16 +0000] "DELETE /api/auth HTTP/1.1" 204 558 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}, @{Timestamp=10/1/2026 8:31:26 AM; Message=ACCESS: 192.168.1.162 - - [01/Oct/2026:13:31:17 +0000] "POST /api/auth HTTP/1.1" 200 807 - Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6; Priority=}…} +NextID : 31 Pid : 388 File : /var/log/pihole/webserver.log ``` @@ -1214,7 +1214,7 @@ Get-PiHoleLogDnsmasq -PiHoleServer $PiHoleServer -Password $Password ``` -Log : {@{Timestamp=9/30/2026 3:18:16 PM; Message=started, version pi-hole-v2.93 cachesize 10000; Priority=}, @{Timestamp=9/30/2026 3:18:16 PM; Message=DNS service limited to local subnets; Priority=}, @{Timestamp=9/30/2026 3:18:16 PM; Message=compile time options: IPv6 GNU-getopt no-DBus no-UBus no-i18n IDN2 DHCP DHCPv6 Lua TFTP no-conntrack ipset no-nftset auth DNSSEC loop-detect inotify dumpfile; Priority=}, @{Timestamp=9/30/2026 3:18:16 PM; Message=using nameserver 8.8.8.8#53; Priority=}…} +Log : {@{Timestamp=10/1/2026 8:28:22 AM; Message=started, version pi-hole-v2.93 cachesize 10000; Priority=}, @{Timestamp=10/1/2026 8:28:22 AM; Message=DNS service limited to local subnets; Priority=}, @{Timestamp=10/1/2026 8:28:22 AM; Message=compile time options: IPv6 GNU-getopt no-DBus no-UBus no-i18n IDN2 DHCP DHCPv6 Lua TFTP no-conntrack ipset no-nftset auth DNSSEC loop-detect inotify dumpfile; Priority=}, @{Timestamp=10/1/2026 8:28:22 AM; Message=using nameserver 8.8.8.8#53; Priority=}…} NextID : 69 Pid : 388 File : /var/log/pihole/pihole.log @@ -1228,8 +1228,8 @@ Get-PiHoleLogFtl -PiHoleServer $PiHoleServer -Password $Password ``` -Log : {@{Timestamp=9/30/2026 3:44:48 PM; Message= -> s_cost: 1024; Priority=DEBUG_API}, @{Timestamp=9/30/2026 3:44:48 PM; Message= -> t_cost: 32; Priority=DEBUG_API}, @{Timestamp=9/30/2026 3:44:48 PM; Message= -> Salt: 'ZM+UIgW0FxI1Ns0FbtOwxg=='; Priority=DEBUG_API}, @{Timestamp=9/30/2026 3:44:48 PM; Message= -> Hash: 'REBNkE/jmdkRF3uyFRUpnxcQCKuSaS3U30DMsqWp0yE='; Priority=DEBUG_API}…} -NextID : 919 +Log : {@{Timestamp=10/1/2026 8:54:42 AM; Message=Wrote config file:; Priority=INFO}, @{Timestamp=10/1/2026 8:54:42 AM; Message= - 167 total entries; Priority=INFO}, @{Timestamp=10/1/2026 8:54:42 AM; Message= - 157 entries are default; Priority=INFO}, @{Timestamp=10/1/2026 8:54:42 AM; Message= - 10 entries are modified; Priority=INFO}…} +NextID : 797 Pid : 388 File : /var/log/pihole/FTL.log ``` @@ -1258,31 +1258,31 @@ Get-PiHoleHistory -PiHoleServer $PiHoleServer -Password $Password ``` -Timestamp : 9/29/2026 4:25:00 PM +Timestamp : 9/30/2026 3:15:00 PM Total : 0 Cached : 0 Blocked : 0 Forwarded : 0 -Timestamp : 9/29/2026 4:35:00 PM +Timestamp : 9/30/2026 3:25:00 PM Total : 0 Cached : 0 Blocked : 0 Forwarded : 0 -Timestamp : 9/29/2026 4:45:00 PM +Timestamp : 9/30/2026 3:35:00 PM Total : 0 Cached : 0 Blocked : 0 Forwarded : 0 -Timestamp : 9/29/2026 4:55:00 PM +Timestamp : 9/30/2026 3:45:00 PM Total : 0 Cached : 0 Blocked : 0 Forwarded : 0 -Timestamp : 9/29/2026 5:05:00 PM +Timestamp : 9/30/2026 3:55:00 PM Total : 0 Cached : 0 Blocked : 0 @@ -1299,19 +1299,19 @@ Get-PiHoleHistoryClient -PiHoleServer $PiHoleServer -Password $Password ``` -Timestamp : 9/29/2026 4:25:00 PM +Timestamp : 9/30/2026 3:15:00 PM Clients : {@{IP=192.168.1.162; Name=; Count=0}, @{IP=others; Name=; Count=0}} -Timestamp : 9/29/2026 4:35:00 PM +Timestamp : 9/30/2026 3:25:00 PM Clients : {@{IP=192.168.1.162; Name=; Count=0}, @{IP=others; Name=; Count=0}} -Timestamp : 9/29/2026 4:45:00 PM +Timestamp : 9/30/2026 3:35:00 PM Clients : {@{IP=192.168.1.162; Name=; Count=0}, @{IP=others; Name=; Count=0}} -Timestamp : 9/29/2026 4:55:00 PM +Timestamp : 9/30/2026 3:45:00 PM Clients : {@{IP=192.168.1.162; Name=; Count=0}, @{IP=others; Name=; Count=0}} -Timestamp : 9/29/2026 5:05:00 PM +Timestamp : 9/30/2026 3:55:00 PM Clients : {@{IP=192.168.1.162; Name=; Count=0}, @{IP=others; Name=; Count=0}} _(showing 5 of 145 results)_ @@ -1327,11 +1327,37 @@ Get-PiHoleHistoryDatabase -PiHoleServer $PiHoleServer -Password $Password ``` -Timestamp : 9/30/2026 4:10:00 PM +Timestamp : 10/1/2026 9:00:00 AM Total : 42 -Cached : 7 -Blocked : 8 +Cached : 5 +Blocked : 10 Forwarded : 27 + +Timestamp : 10/1/2026 10:00:00 AM +Total : 3 +Cached : 3 +Blocked : 0 +Forwarded : 0 + +Timestamp : 10/1/2026 11:00:00 AM +Total : 3 +Cached : 3 +Blocked : 0 +Forwarded : 0 + +Timestamp : 10/1/2026 12:00:00 PM +Total : 1 +Cached : 1 +Blocked : 0 +Forwarded : 0 + +Timestamp : 10/1/2026 1:00:00 PM +Total : 1 +Cached : 1 +Blocked : 0 +Forwarded : 0 + +_(showing 5 of 7 results)_ ``` ### Get-PiHoleHistoryDatabaseClient @@ -1344,8 +1370,22 @@ Get-PiHoleHistoryDatabaseClient -PiHoleServer $PiHoleServer -Password $Password ``` -Timestamp : 9/30/2026 4:10:00 PM -Clients : {@{ClientId=3; Count=1}, @{ClientId=2; Count=1}, @{ClientId=5; Count=1}} +Timestamp : 10/1/2026 3:00:00 PM +Clients : @{ClientId=3; Count=1} + +Timestamp : 10/1/2026 2:00:00 PM +Clients : @{ClientId=3; Count=1} + +Timestamp : 10/1/2026 1:00:00 PM +Clients : @{ClientId=3; Count=1} + +Timestamp : 10/1/2026 12:00:00 PM +Clients : @{ClientId=3; Count=1} + +Timestamp : 10/1/2026 11:00:00 AM +Clients : @{ClientId=3; Count=1} + +_(showing 5 of 7 results)_ ``` ### Get-PiHoleNetworkGateway @@ -1454,7 +1494,7 @@ Address : b8:27:eb:11:a4:d5 Broadcast : ff:ff:ff:ff:ff:ff PermAddress : b8:27:eb:11:a4:d5 Stats : @{RxBytes=; TxBytes=; Bits=64} -Addresses : {@{Family=inet; Scope=universe; Flags=; Prefixlen=24; Address=192.168.1.248; AddressType=private; Local=192.168.1.248; LocalType=private; Broadcast=192.168.1.255; BroadcastType=private; Label=wlan0; Prefered=76172; Valid=76172; Cstamp=1790649687.41; Tstamp=1790793450.81}, @{Family=inet6; Scope=link; Flags=permanent; Prefixlen=64; Address=fe80::ba27:ebff:fe11:a4d5; AddressType=link-local (LL); Prefered=4294967295; Valid=4294967295; Cstamp=1790649682.83; Tstamp=1790649682.83}} +Addresses : {@{Family=inet; Scope=universe; Flags=; Prefixlen=24; Address=192.168.1.248; AddressType=private; Local=192.168.1.248; LocalType=private; Broadcast=192.168.1.255; BroadcastType=private; Label=wlan0; Prefered=63266; Valid=63266; Cstamp=1790649687.41; Tstamp=1790862827.1}, @{Family=inet6; Scope=link; Flags=permanent; Prefixlen=64; Address=fe80::ba27:ebff:fe11:a4d5; AddressType=link-local (LL); Prefered=4294967295; Valid=4294967295; Cstamp=1790649682.83; Tstamp=1790649682.83}} ``` ### Get-PiHoleNetworkDevice @@ -1470,20 +1510,20 @@ Get-PiHoleNetworkDevice -PiHoleServer $PiHoleServer -Password $Password Id : 2 HwAddr : ip-127.0.0.1 Interface : lo -FirstSeen : 9/30/2026 4:19:27 PM -LastQuery : 9/30/2026 4:19:28 PM -NumQueries : 3 +FirstSeen : 10/1/2026 9:03:33 AM +LastQuery : 10/1/2026 3:00:00 PM +NumQueries : 13 MacVendor : -Ips : @{Ip=127.0.0.1; Name=localhost; LastSeen=9/30/2026 4:28:00 PM; NameUpdated=9/30/2026 4:28:00 PM} +Ips : @{Ip=127.0.0.1; Name=localhost; LastSeen=10/1/2026 3:19:00 PM; NameUpdated=10/1/2026 3:19:00 PM} Id : 1 HwAddr : 74:56:3c:bb:f4:0b Interface : wlan0 -FirstSeen : 9/30/2026 4:19:27 PM -LastQuery : 9/30/2026 4:19:27 PM +FirstSeen : 10/1/2026 9:03:32 AM +LastQuery : 10/1/2026 9:03:33 AM NumQueries : 39 MacVendor : Giga-Byte Technology Co.,Ltd. -Ips : @{Ip=192.168.1.162; Name=; LastSeen=9/30/2026 4:28:00 PM; NameUpdated=12/31/1969 6:00:00 PM} +Ips : @{Ip=192.168.1.162; Name=; LastSeen=10/1/2026 3:19:00 PM; NameUpdated=12/31/1969 6:00:00 PM} ``` ### Remove-PiHoleNetworkDevice @@ -1524,6 +1564,43 @@ Error : Response status code does not indicate success: 400 (Bad Request). ## Authentication +### Get-PiHoleAuthStatus + +_Password is optional - omit it to check whether your Pi-hole requires a login at all for this client, without authenticating. This test server does require login, so the result below is from a real authenticated check._ + +```powershell +Get-PiHoleAuthStatus -PiHoleServer $PiHoleServer -Password $Password +``` + +``` + +Valid : True +Totp : False +Sid : 8sHZ0t+C5DwLRgIcKIM7/g= +Csrf : 1xmNq2FNUPFo7bnCRoUzIQ= +Validity : 1800 +Message : correct password +``` + +### Get-PiHoleAuthTotp + +```powershell +Get-PiHoleAuthTotp -PiHoleServer $PiHoleServer -Password $Password +``` + +``` + +Type : totp +Account : pi.hole +Issuer : Pi-hole%20API +Algorithm : SHA1 +Digits : 6 +Period : 30 +Offset : 0 +Secret : XP4YEGF2S75KCDBN7BSW37AEA65AQZBQ +Codes : {414882, 273855, 226959, 897753…} +``` + ### Get-PiHoleCurrentAuthSession ```powershell @@ -1533,27 +1610,13 @@ Get-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Password $Password ``` Id : 0 -CurrentSession : False -Valid : True -TlsLogin : True -TlsMixed : False -LoginAt : 9/30/2026 4:16:56 PM -LastActive : 9/30/2026 4:16:56 PM -ValidUntil : 9/30/2026 4:46:56 PM -RemoteAddress : 192.168.1.162 -UserAgent : Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6 -XForwardedFor : -App : True -Cli : False - -Id : 1 CurrentSession : True Valid : True TlsLogin : True TlsMixed : False -LoginAt : 9/30/2026 4:19:34 PM -LastActive : 9/30/2026 4:19:39 PM -ValidUntil : 9/30/2026 4:49:39 PM +LoginAt : 10/1/2026 3:10:59 PM +LastActive : 10/1/2026 3:11:03 PM +ValidUntil : 10/1/2026 3:41:03 PM RemoteAddress : 192.168.1.162 UserAgent : Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.26200; en-US) PowerShell/7.6.6 XForwardedFor : @@ -1566,13 +1629,13 @@ Cli : False _Deletes a session by its ID (as shown by Get-PiHoleCurrentAuthSession), not the caller's own session._ ```powershell -Remove-PiHoleAuthSession -PiHoleServer $PiHoleServer -Password $Password -Id 1 +Remove-PiHoleAuthSession -PiHoleServer $PiHoleServer -Password $Password -Id 0 ``` ``` -Id : 1 +Id : 0 Status : Removed ``` diff --git a/tests/Authentication/Get-PiHoleAuthStatus.Integration.Tests.ps1 b/tests/Authentication/Get-PiHoleAuthStatus.Integration.Tests.ps1 new file mode 100644 index 0000000..26adfa0 --- /dev/null +++ b/tests/Authentication/Get-PiHoleAuthStatus.Integration.Tests.ps1 @@ -0,0 +1,51 @@ +# Requires -Module Pester +# +# Integration tests that call a REAL Pi-hole server. Configure tests/IntegrationConfig.local.ps1 +# (copy it from IntegrationConfig.example.ps1) before running. Tests are skipped automatically +# if that file is missing. + +$script:ConfigAvailable = Test-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'IntegrationConfig.local.ps1') + +Describe 'Get-PiHoleAuthStatus (Integration)' -Tag 'Integration' { + BeforeAll { + Import-Module .\PiHoleShell\PiHoleShell.psm1 -Force + + $configPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'IntegrationConfig.local.ps1' + if (Test-Path $configPath) { + . $configPath + $script:PiHoleServer = $PiHoleServer + $script:PiHoleToken = $PiHoleToken + $script:PiHoleIgnoreSsl = $PiHoleIgnoreSsl + } + } + + It 'returns a valid session when given a real password' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthStatus -PiHoleServer $script:PiHoleServer -Password $script:PiHoleToken -IgnoreSsl $script:PiHoleIgnoreSsl + $result | Format-List | Out-String | Write-Host + + $result | Should -Not -BeNullOrEmpty + $result.Valid | Should -BeTrue + } + + # This test server requires a login for API clients, so calling with no password at all is + # expected to fail - this still exercises the real anonymous-check code path. A Pi-hole + # configured to skip auth for trusted local clients would instead return a valid session here. + It 'errors when called with no password and the server requires login' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthStatus -PiHoleServer $script:PiHoleServer -IgnoreSsl $script:PiHoleIgnoreSsl -ErrorVariable errOut -ErrorAction SilentlyContinue + + $errOut | Should -Not -BeNullOrEmpty + } + + It 'returns the raw API response when RawOutput is set' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthStatus -PiHoleServer $script:PiHoleServer -Password $script:PiHoleToken -IgnoreSsl $script:PiHoleIgnoreSsl -RawOutput $true + $result | Format-List | Out-String | Write-Host + + $result.PSObject.Properties.Name | Should -Contain 'session' + } + + It 'errors when given a bad password' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthStatus -PiHoleServer $script:PiHoleServer -Password 'definitely-not-the-real-token' -IgnoreSsl $script:PiHoleIgnoreSsl -ErrorVariable errOut -ErrorAction SilentlyContinue + + $errOut | Should -Not -BeNullOrEmpty + } +} diff --git a/tests/Authentication/Get-PiHoleAuthTotp.Integration.Tests.ps1 b/tests/Authentication/Get-PiHoleAuthTotp.Integration.Tests.ps1 new file mode 100644 index 0000000..90ac40d --- /dev/null +++ b/tests/Authentication/Get-PiHoleAuthTotp.Integration.Tests.ps1 @@ -0,0 +1,42 @@ +# Requires -Module Pester +# +# Integration tests that call a REAL Pi-hole server. Configure tests/IntegrationConfig.local.ps1 +# (copy it from IntegrationConfig.example.ps1) before running. Tests are skipped automatically +# if that file is missing. + +$script:ConfigAvailable = Test-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'IntegrationConfig.local.ps1') + +Describe 'Get-PiHoleAuthTotp (Integration)' -Tag 'Integration' { + BeforeAll { + Import-Module .\PiHoleShell\PiHoleShell.psm1 -Force + + $configPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'IntegrationConfig.local.ps1' + if (Test-Path $configPath) { + . $configPath + $script:PiHoleServer = $PiHoleServer + $script:PiHoleToken = $PiHoleToken + $script:PiHoleIgnoreSsl = $PiHoleIgnoreSsl + } + } + + It 'returns a suggested TOTP secret as a formatted object' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthTotp -PiHoleServer $script:PiHoleServer -Password $script:PiHoleToken -IgnoreSsl $script:PiHoleIgnoreSsl + $result | Format-List | Out-String | Write-Host + + $result | Should -Not -BeNullOrEmpty + $result.Secret | Should -Not -BeNullOrEmpty + } + + It 'returns the raw API response when RawOutput is set' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthTotp -PiHoleServer $script:PiHoleServer -Password $script:PiHoleToken -IgnoreSsl $script:PiHoleIgnoreSsl -RawOutput $true + $result | Format-List | Out-String | Write-Host + + $result.PSObject.Properties.Name | Should -Contain 'totp' + } + + It 'errors when given a bad password' -Skip:(-not $script:ConfigAvailable) { + $result = Get-PiHoleAuthTotp -PiHoleServer $script:PiHoleServer -Password 'definitely-not-the-real-token' -IgnoreSsl $script:PiHoleIgnoreSsl -ErrorVariable errOut -ErrorAction SilentlyContinue + + $errOut | Should -Not -BeNullOrEmpty + } +} diff --git a/tools/Update-ExampleOutput.ps1 b/tools/Update-ExampleOutput.ps1 index 4da478d..865609d 100644 --- a/tools/Update-ExampleOutput.ps1 +++ b/tools/Update-ExampleOutput.ps1 @@ -108,6 +108,15 @@ function Invoke-Quietly { Write-Host "Capturing example output against $PiHoleServer ..." #region Authentication +Add-Example -Category Authentication -FunctionName 'Get-PiHoleAuthStatus' ` + -Invocation 'Get-PiHoleAuthStatus -PiHoleServer $PiHoleServer -Password $Password' ` + -Note 'Password is optional - omit it to check whether your Pi-hole requires a login at all for this client, without authenticating. This test server does require login, so the result below is from a real authenticated check.' ` + -Result (Get-PiHoleAuthStatus -PiHoleServer $PiHoleServer -Password $PiHoleToken -IgnoreSsl $PiHoleIgnoreSsl) + +Add-Example -Category Authentication -FunctionName 'Get-PiHoleAuthTotp' ` + -Invocation 'Get-PiHoleAuthTotp -PiHoleServer $PiHoleServer -Password $Password' ` + -Result (Get-PiHoleAuthTotp -PiHoleServer $PiHoleServer -Password $PiHoleToken -IgnoreSsl $PiHoleIgnoreSsl) + Add-Example -Category Authentication -FunctionName 'Get-PiHoleCurrentAuthSession' ` -Invocation 'Get-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Password $Password' ` -Result (Get-PiHoleCurrentAuthSession -PiHoleServer $PiHoleServer -Password $PiHoleToken -IgnoreSsl $PiHoleIgnoreSsl)