diff --git a/PiHoleShell/PiHoleShell.psd1 b/PiHoleShell/PiHoleShell.psd1 index 7d2fbdd..63feccc 100644 Binary files a/PiHoleShell/PiHoleShell.psd1 and b/PiHoleShell/PiHoleShell.psd1 differ diff --git a/PiHoleShell/Private/Misc.ps1 b/PiHoleShell/Private/Misc.ps1 index 8ac74df..b0c7772 100644 --- a/PiHoleShell/Private/Misc.ps1 +++ b/PiHoleShell/Private/Misc.ps1 @@ -45,47 +45,4 @@ function Convert-LocalTimeToPiHoleUnixTime { $ObjectFinal = $Object Write-Output $ObjectFinal -} - -# function Test-HttpPrefixForPiHole { -# param ( -# [Parameter(Mandatory)] -# [string]$Url -# ) - -# Write-Output ($Url -match '^https?://') -# } - -# function Test-PiHoleServerAccess { -# param ( -# [Parameter(Mandatory)] -# [string]$Url, -# [bool]$IgnoreSsl = $false -# ) - -# if (Test-HttpPrefixForPiHole -Url $Url) { -# $RawOutput = Invoke-WebRequest -Uri "$Url/admin/login" -Method Head -TimeoutSec 5 -ErrorAction Stop -SkipCertificateCheck -# } -# } - -# function Convert-EnabledBoolToString { -# param ( -# [bool]$Bool -# ) - -# switch ($Bool) { -# $false { -# $Enabled = "false" -# } -# $true { -# $Enabled = "true" -# } -# } - -# $Object = [PSCustomObject]@{ -# Bool = $Enabled -# } - -# Write-Output $Object - -# } \ No newline at end of file +} \ No newline at end of file diff --git a/PiHoleShell/Public/Authentication.ps1 b/PiHoleShell/Public/Authentication.ps1 index 6eb1263..b3cc3a2 100644 --- a/PiHoleShell/Public/Authentication.ps1 +++ b/PiHoleShell/Public/Authentication.ps1 @@ -18,6 +18,7 @@ function Request-PiHoleAuth { } $Response = Invoke-RestMethod @Params -Verbose: $false + Write-Verbose -Message "Request-PiHoleAuth Successful!" Write-Output $Response.session.sid } @@ -39,14 +40,22 @@ The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "h .PARAMETER Password The API Password you generated from your PiHole v6 server +.PARAMETER IgnoreSsl +Ignore SSL when interacting with the PiHole API + +.PARAMETER RawOutput +This will dump the response instead of the formatted object + .EXAMPLE Get-PiHoleCurrentAuthSession -PiHoleServer "http://pihole.domain.com:8080" -Password "fjdsjfldsjfkldjslafjskdl" #> [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( - [string]$PiHoleServer, - $Password, + [Parameter(Mandatory = $true)] + [System.URI]$PiHoleServer, + [Parameter(Mandatory = $true)] + [string]$Password, [bool]$IgnoreSsl = $false, [bool]$RawOutput = $false ) @@ -55,7 +64,7 @@ Get-PiHoleCurrentAuthSession -PiHoleServer "http://pihole.domain.com:8080" -Pass $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/auth/sessions" + Uri = "$($PiHoleServer.OriginalString)/api/auth/sessions" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -117,7 +126,7 @@ function Remove-PiHoleCurrentAuthSession { ) $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/auth" + Uri = "$($PiHoleServer.OriginalString)/api/auth" Method = "Delete" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -143,15 +152,20 @@ The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "h .PARAMETER Password The API Password you generated from your PiHole server +.PARAMETER IgnoreSsl +Ignore SSL when interacting with the PiHole API + .EXAMPLE Get-PiHoleCurrentAuthSession -PiHoleServer "http://pihole.domain.com:8080" -Password "fjdsjfldsjfkldjslafjskdl" #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Does not change state')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( - $PiHoleServer, - $Password, - $IgnoreSsl, + [Parameter(Mandatory = $true)] + [System.URI]$PiHoleServer, + [Parameter(Mandatory = $true)] + [string]$Password, + [bool]$IgnoreSsl = $false, [int]$Id ) @@ -159,7 +173,7 @@ Get-PiHoleCurrentAuthSession -PiHoleServer "http://pihole.domain.com:8080" -Pass $Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/auth/session/$Id" + Uri = "$($PiHoleServer.OriginalString)/api/auth/session/$Id" Method = "Delete" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" diff --git a/PiHoleShell/Public/Config.ps1 b/PiHoleShell/Public/Config.ps1 index 07462f8..1ca4ad0 100644 --- a/PiHoleShell/Public/Config.ps1 +++ b/PiHoleShell/Public/Config.ps1 @@ -8,8 +8,10 @@ https://TODO [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( - $PiHoleServer, - $Password, + [Parameter(Mandatory = $true)] + [System.URI]$PiHoleServer, + [Parameter(Mandatory = $true)] + [string]$Password, [bool]$IgnoreSsl = $false, [bool]$RawOutput = $false ) @@ -17,7 +19,7 @@ https://TODO $Sid = Request-PiHoleAuth -PiHoleServer $PiHoleServer -Password $Password -IgnoreSsl $IgnoreSsl $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/config" + Uri = "$($PiHoleServer.OriginalString)/api/config" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" diff --git a/PiHoleShell/Public/DnsControl.ps1 b/PiHoleShell/Public/DnsControl.ps1 index cca20bf..146247d 100644 --- a/PiHoleShell/Public/DnsControl.ps1 +++ b/PiHoleShell/Public/DnsControl.ps1 @@ -1,7 +1,7 @@ function Get-PiHoleDnsBlockingStatus { <# .SYNOPSIS -https://ftl.pi-hole.net/development-v6/docs/#get-/dns/blocking +Get current blocking status .PARAMETER PiHoleServer The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "http://192.168.1.100" @@ -9,6 +9,9 @@ The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "h .PARAMETER Password The API Password you generated from your PiHole server +.PARAMETER IgnoreSsl +Ignore SSL when interacting with the PiHole API + .PARAMETER RawOutput This will dump the response instead of the formatted object @@ -18,7 +21,7 @@ Get-PiHoleDnsBlockingStatus -PiHoleServer "http://pihole.domain.com:8080" -Passw [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [bool]$IgnoreSsl = $false, @@ -29,7 +32,7 @@ Get-PiHoleDnsBlockingStatus -PiHoleServer "http://pihole.domain.com:8080" -Passw $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/dns/blocking" + Uri = "$($PiHoleServer.OriginalString)/api/dns/blocking" Method = "Get" ContentType = "application/json" SkipCertificateCheck = $IgnoreSsl @@ -94,7 +97,7 @@ Set-PiHoleDnsBlocking -PiHoleServer "http://pihole.domain.com:8080" -Password "f [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [ValidateSet("True", "False")] @@ -111,13 +114,14 @@ Set-PiHoleDnsBlocking -PiHoleServer "http://pihole.domain.com:8080" -Password "f $Body = "{`"blocking`":$Blocking,`"timer`":$TimeInSeconds}" $Params = @{ - Headers = @{sid = $($Sid) + Headers = @{sid = $($Sid) Accept = "application/json" } - Uri = "$PiHoleServer/api/dns/blocking" - Method = "Post" - ContentType = "application/json" - Body = $Body + Uri = "$($PiHoleServer.OriginalString)/api/dns/blocking" + Method = "Post" + ContentType = "application/json" + Body = $Body + SkipCertificateCheck = $IgnoreSsl } $Response = Invoke-RestMethod @Params diff --git a/PiHoleShell/Public/GroupManagement.ps1 b/PiHoleShell/Public/GroupManagement.ps1 index 8d9a52d..a7d3c7a 100644 --- a/PiHoleShell/Public/GroupManagement.ps1 +++ b/PiHoleShell/Public/GroupManagement.ps1 @@ -96,7 +96,7 @@ https://TODO [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [Parameter(Mandatory = $true)] @@ -125,7 +125,7 @@ https://TODO $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/groups" + Uri = "$($PiHoleServer.OriginalString)/api/groups" Method = "Post" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -176,7 +176,7 @@ https://TODO [Diagnostics.CodeAnalysis.SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "", Justification = "Ignoring for now")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [Parameter(Mandatory = $true)] @@ -229,7 +229,7 @@ https://TODO $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/groups/$GroupName" + Uri = "$($PiHoleServer.OriginalString)/api/groups/$GroupName" Method = "Put" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -282,7 +282,7 @@ https://TODO [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [Parameter(Mandatory = $true)] @@ -300,7 +300,7 @@ https://TODO $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/groups/$GroupName" + Uri = "$($PiHoleServer.OriginalString)/api/groups/$GroupName" Method = "Delete" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" diff --git a/PiHoleShell/Public/Metrics.ps1 b/PiHoleShell/Public/Metrics.ps1 index b012841..221ef7d 100644 --- a/PiHoleShell/Public/Metrics.ps1 +++ b/PiHoleShell/Public/Metrics.ps1 @@ -23,7 +23,7 @@ Get-PiHoleStatsRecentBlocked -PiHoleServer "http://pihole.domain.com:8080" -Pass [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [int]$MaxResult = 1, @@ -35,7 +35,7 @@ Get-PiHoleStatsRecentBlocked -PiHoleServer "http://pihole.domain.com:8080" -Pass Write-Verbose -Message "MaxResults - $MaxResult" $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/stats/recent_blocked?count=$MaxResult" + Uri = "$($PiHoleServer.OriginalString)/api/stats/recent_blocked?count=$MaxResult" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -81,7 +81,7 @@ https://TODOFINDNEWAPILINK [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [bool]$IgnoreSsl = $false, @@ -92,7 +92,7 @@ https://TODOFINDNEWAPILINK Write-Verbose -Message "MaxResults - $MaxResult" $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/stats/query_types" + Uri = "$($PiHoleServer.OriginalString)/api/stats/query_types" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -136,7 +136,7 @@ https://TODOFINDNEWAPILINK [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [int]$MaxResult = 10, @@ -162,7 +162,7 @@ https://TODOFINDNEWAPILINK $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/stats/top_domains?blocked=$Blocked&count=$MaxResult" + Uri = "$($PiHoleServer.OriginalString)/api/stats/top_domains?blocked=$Blocked&count=$MaxResult" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" @@ -191,7 +191,7 @@ The URL to the PiHole Server, for example "http://pihole.domain.com:8080", or "h .PARAMETER Password The API Password you generated from your PiHole server -.PARAMETER IgnoreSsl + This will dump the response instead of the formatted object .PARAMETER RawOutput @@ -204,7 +204,7 @@ Get-PiHoleStatsSummary -PiHoleServer "http://pihole.domain.com:8080" -Password " [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Password")] param ( [Parameter(Mandatory = $true)] - [string]$PiHoleServer, + [System.URI]$PiHoleServer, [Parameter(Mandatory = $true)] [string]$Password, [bool]$IgnoreSsl = $false, @@ -215,7 +215,7 @@ Get-PiHoleStatsSummary -PiHoleServer "http://pihole.domain.com:8080" -Password " $Params = @{ Headers = @{sid = $($Sid) } - Uri = "$PiHoleServer/api/stats/summary" + Uri = "$($PiHoleServer.OriginalString)/api/stats/summary" Method = "Get" SkipCertificateCheck = $IgnoreSsl ContentType = "application/json" diff --git a/tests/Set-PiHoleDnsBlocking.Tests.ps1 b/tests/Set-PiHoleDnsBlocking.Tests.ps1 new file mode 100644 index 0000000..4f31a2f --- /dev/null +++ b/tests/Set-PiHoleDnsBlocking.Tests.ps1 @@ -0,0 +1,54 @@ +# Requires -Module Pester +Describe 'Set-PiHoleDnsBlocking' { + BeforeAll { + # Sample input values + $server = [uri]'http://pihole.local' + $password = 'mock-password' + $sid = 'mock-session-id' + + # Mock external functions + Mock -CommandName Request-PiHoleAuth -MockWith { return $sid } + Mock -CommandName Remove-PiHoleCurrentAuthSession + Mock -CommandName Format-PiHoleSecond -MockWith { + return @{ TimeInSeconds = 60 } + } + + # Mock response from API + Mock -CommandName Invoke-RestMethod -MockWith { + return @{ + blocking = 'false' + timer = 60 + } + } + } + + It 'should call Request-PiHoleAuth and send correct POST body' { + Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 | Out-Null + + # Assert internal functions were called correctly + Assert-MockCalled Request-PiHoleAuth -Times 1 -Exactly -Scope It + Assert-MockCalled Invoke-RestMethod -Times 1 -Scope It + Assert-MockCalled Remove-PiHoleCurrentAuthSession -Times 1 -Scope It + } + + It 'should return a formatted PSCustomObject if RawOutput is $false' { + $result = Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 + $result | Should -BeOfType 'System.Object[]' + $result[0].Blocking | Should -Be 'false' + $result[0].TimeInSeconds | Should -Be 60 + } + + It 'should return raw response if RawOutput is $true' { + $result = Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 -RawOutput + $result | Should -HaveProperty 'blocking' + $result | Should -HaveProperty 'timer' + } + + It 'should handle errors and output them' { + # Mock to simulate error + Mock -CommandName Invoke-RestMethod -MockWith { throw "Test error" } -ParameterFilter { $Body -like '*' } + + { Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' } | + Should -Throw -ErrorMessage 'Test error' + } +}